0

設定された長さ (たとえば常に 5 文字) の一連の英字識別子があり、それらが常に順次インクリメントされるように割り当てられているとします (GGGGZ --> GGGHA など)。さて、ZZZZZまで来たら、長さが決まっているので、AAAAまで「ロールオーバー」しなければなりません。ZZZAA から AAAAM までの連続したブロックがある可能性があります。「次の」識別子、この場合は AAAAN を与える sproc を書きたいと思います。

もちろん、この「ロール オーバー」の問題がなければ、ORDER BY DESC で一番上の結果を取得します。しかし、私は今、少し途方に暮れています.SQLが私の最強の言語ではないことはまったく役に立ちません.

必要に応じて、これを C# 呼び出しコードに移動できますが、sproc の方が適しています。

ETA: スキーマ (新しい列または新しいテーブル)を変更したくありません。私はむしろ「それを理解する」ことができればいいのにと思います。コストが高くなる可能性はありますが、力ずくで行うことを好むかもしれません (たとえば、最小値から始めて「穴」が見つかるまでインクリメントする)。スキーマを変更しない回答があれば、それが私のニーズにとってより良い解決策になるでしょう。

4

7 に答える 7

1

次の値が得られると思われるコードを次に示します。3つの関数を作成しました。このテーブルは、アルファ ID を使用した table.column の単なるシミュレーションです (MyTable.AlphaID を使用しました)。あなたが暗示したとおりであり、5文字の大文字のアルファベット文字列(AlphaID)の連続したブロックが1つあると思います:

IF OBJECT_ID('dbo.MyTable','U') IS NOT NULL
    DROP TABLE dbo.MyTable
GO
CREATE TABLE dbo.MyTable (AlphaID char(5) PRIMARY KEY)
GO
-- Play with different population scenarios for testing
INSERT dbo.MyTable VALUES ('ZZZZY')
INSERT dbo.MyTable VALUES ('ZZZZZ')
INSERT dbo.MyTable VALUES ('AAAAA')
INSERT dbo.MyTable VALUES ('AAAAB')
GO
IF OBJECT_ID('dbo.ConvertAlphaIDToInt','FN') IS NOT NULL
    DROP FUNCTION dbo.ConvertAlphaIDToInt
GO
CREATE FUNCTION dbo.ConvertAlphaIDToInt (@AlphaID char(5))
RETURNS int
AS
BEGIN
RETURN 1+ ASCII(SUBSTRING(@AlphaID,5,1))-65
              + ((ASCII(SUBSTRING(@AlphaID,4,1))-65) * 26)
              + ((ASCII(SUBSTRING(@AlphaID,3,1))-65) * POWER(26,2))
              + ((ASCII(SUBSTRING(@AlphaID,2,1))-65) * POWER(26,3))
              + ((ASCII(SUBSTRING(@AlphaID,1,1))-65) * POWER(26,4))
END
GO 

IF OBJECT_ID('dbo.ConvertIntToAlphaID','FN') IS NOT NULL
    DROP FUNCTION dbo.ConvertIntToAlphaID
GO
CREATE FUNCTION dbo.ConvertIntToAlphaID (@ID int)
RETURNS char(5)
AS
BEGIN
RETURN CHAR((@ID-1) / POWER(26,4) + 65)
      + CHAR ((@ID-1) % POWER(26,4) / POWER(26,3) + 65)
      + CHAR ((@ID-1) % POWER(26,3) / POWER(26,2) + 65)
      + CHAR ((@ID-1) % POWER(26,2) / 26 + 65)
      + CHAR ((@ID-1) % 26 + 65)

END
GO 
IF OBJECT_ID('dbo.GetNextAlphaID','FN') IS NOT NULL
    DROP FUNCTION dbo.GetNextAlphaID
GO
CREATE FUNCTION dbo.GetNextAlphaID ()
RETURNS char(5)
AS
BEGIN
    DECLARE @MaxID char(5), @ReturnVal char(5)
    SELECT @MaxID = MAX(AlphaID) FROM dbo.MyTable
    IF @MaxID < 'ZZZZZ'
        RETURN dbo.ConvertIntToAlphaID(dbo.ConvertAlphaIDToInt(@MaxID)+1)
    IF @MaxID IS NULL
        RETURN 'AAAAA'
    SELECT @MaxID = MAX(AlphaID) 
    FROM dbo.MyTable 
    WHERE AlphaID < dbo.ConvertIntToAlphaID((SELECT COUNT(*) FROM dbo.MyTable))
    IF @MaxID IS NULL
        RETURN 'AAAAA'
    RETURN dbo.ConvertIntToAlphaID(dbo.ConvertAlphaIDToInt(@MaxID)+1)
END
GO

SELECT * FROM dbo.MyTable ORDER BY dbo.ConvertAlphaIDToInt(AlphaID)
GO
SELECT  dbo.GetNextAlphaID () AS 'NextAlphaID'

ちなみに、連続性を想定したくない場合は、提案したとおりに実行できます(「ZZZZZ」行がある場合)シーケンスの最初のギャップを使用します。最後の関数を次のように置き換えます。

IF OBJECT_ID('dbo.GetNextAlphaID_2','FN') IS NOT NULL
    DROP FUNCTION dbo.GetNextAlphaID_2
GO
CREATE FUNCTION dbo.GetNextAlphaID_2 ()
RETURNS char(5)
AS
BEGIN
    DECLARE @MaxID char(5), @ReturnVal char(5)
    SELECT @MaxID = MAX(AlphaID) FROM dbo.MyTable
    IF @MaxID < 'ZZZZZ'
        RETURN dbo.ConvertIntToAlphaID(dbo.ConvertAlphaIDToInt(@MaxID)+1)
    IF @MaxID IS NULL
        RETURN 'AAAAA'
    SELECT TOP 1 @MaxID=M1.AlphaID
    FROM dbo.Mytable M1
    WHERE NOT EXISTS (SELECT 1 FROM dbo.MyTable M2 
                      WHERE AlphaID = dbo.ConvertIntToAlphaID(dbo.ConvertAlphaIDToInt(M1.AlphaID) + 1 )
                     )
    ORDER BY M1.AlphaID
    IF @MaxID IS NULL
        RETURN 'AAAAA'
    RETURN dbo.ConvertIntToAlphaID(dbo.ConvertAlphaIDToInt(@MaxID)+1)
END
GO
于 2009-04-02T21:08:46.477 に答える
0

私のニーズに対する影響が最も少ない解決策は、ID 列を追加することだと思います。私が保証できることの 1 つは、「最初に来る」必要があるエントリが最初に追加されるような順序になることです。識別子 BBBB を持つエントリを追加することは決してなく、後で戻って BBBA を追加することはありません。その制約がなければ、明らかに機能しませんが、現状では、id 列で並べ替えるだけで、必要な並べ替えを取得できます。

他の提案についても考え続けます。頭の中で「クリック」すれば、より良い選択肢のように見えるかもしれません。

于 2009-04-09T13:18:25.723 に答える
0

文字をインクリメントするコードを書きたくないので、すべての有効な ID (AAAAAA から ZZZZZZ まで) のテーブルを作成し、それらの ID を 1 から X までの整数で表します。次に、以下を使用できます。

SELECT @max_id = MAX(id) FROM Possible_Silly_IDs

SELECT
    COALESCE(MAX(PSI2.silly_id), 'AAAAAA')
FROM
    My_Table T1
INNER JOIN Possible_Silly_IDs PSI1 ON
    PSI1.silly_id = T1.silly_id
INNER JOIN Possible_Silly_IDs PSI2 ON
    PSI2.id = CASE WHEN PSI1.id = @max_id THEN 1 ELSE PSI1.id + 1 END
LEFT OUTER JOIN My_Table T2 ON
    T2.silly_id = PSI2.silly_id
WHERE
    T2.silly_id IS NULL

テーブルが空の場合に備えて、COALESCE があります。本当に堅牢であるためには、「番号付け」アルゴリズムが変更された場合に備えて、「AAAAAA」 (SELECT @min_silly_id = silly_id WHERE id = 1) を計算する必要があります。

本当に正しいことをしたいのであれば、提案されているようにデータベースの設計をやり直すでしょう。

于 2009-04-02T18:23:40.913 に答える
0

最後に割り当てられた識別子をシーケンスに保存する必要があります。

たとえば、1 つの列と 1 つの行を持つ別のテーブルに格納します。

CREATE TABLE CurrentMaxId (
    Id CHAR(6) NOT NULL
);

INSERT INTO CurrentMaxId (Id) VALUES ('AAAAAA');

新しい識別子を割り当てるたびに、その小さなテーブルの値を取得してインクリメントし、その値をメイン テーブルに格納するだけでなく、.xml の値を更新しますCurrentMaxId

並行性、テーブルロックなどに関しては、通常の警告が適用されます。

于 2009-04-02T16:52:59.260 に答える
0

シーケンスを整数として保存してから、文字列に変換しようとしたと思います。または、アルファ値と同時にインクリメントされる並列整数列を保存します。どちらの方法でも、整数列で並べ替えることができます。

于 2009-04-02T16:53:25.467 に答える
0

ID与えられたID(ロールオーバーを伴う)の次を返すには、次を使用します。

SELECT  COALESCE
        (
        (
        SELECT  TOP 1 id
        FROM    mytable
        WHERE   id > @id
        ORDER BY
                id
        ),
        (
        SELECT  TOP 1 id
        FROM    mytable
        ORDER BY
                id
        )
        ) AS nextid

IDこのクエリは、指定されたの次を検索します。そのようなものがない場合IDは、最初のものを返しますID

結果は次のとおりです。

WITH mytable AS
        (
        SELECT  'AAA' AS id
        UNION ALL
        SELECT  'BBB' AS id
        UNION ALL
        SELECT  'CCC' AS id
        UNION ALL
        SELECT  'DDD' AS id
        UNION ALL
        SELECT  'EEE' AS id
        )
SELECT  mo.id,
        COALESCE
        (
        (
        SELECT  TOP 1 id
        FROM    mytable mi
        WHERE   mi.id > mo.id
        ORDER BY
                id
        ),
        (
        SELECT  TOP 1 id
        FROM    mytable mi
        ORDER BY
                id
        )
        ) AS nextid
FROM    mytable mo

id      nextid
-----   ------
AAA     BBB
BBB     CCC
CCC     DDD
DDD     EEE
EEE     AAA

、つまり、 BBBfor AAACCCforBBBなどを返し、最後に、表の最後にあるAAAforを返します。EEE

于 2009-04-03T17:53:15.910 に答える