SQL Server存储过程:遍历表,比较值,在值变化时插入不同的表

时间:2014-03-05 15:35:45

标签: sql sql-server stored-procedures comparison

我无法判断我的特定情况是否已经涵盖了其他问题的标题,如果答案已经存在,那么道歉。

我有一个数据库,它将值记录为字符串,另一个表记录了这些值中特定类型的运行。

我需要一个迭代值的存储过程(我理解这与游标的概念有关),将每个值记录到临时表以控制特定运行类型的计数(奇数/偶数,例如,或元音/辅音)。当给定值指示特定类型的运行已停止时(即奇数停止了偶数运行,反之亦然),运行计数,计数被插入到具有相关类型值的运行表中(0 = odd / even,1 =元音/辅音等),删除临时表内容,并将导致表计数/清除的值插入临时表。

由于我对存储过程完全不熟悉,我不知道如何构建这种过程,我发现的例子不是:

  • 描述如何以简单易懂的方式实现游标
  • 深入了解给定值与存储的比较值之间的比较
  • 允许识别已建立模式的更改以启动过程的一部分

如果有任何需要澄清,请告诉我。

编辑:

正在使用的版本:MS SQL Server 2012

原始值的表结构:

ID: Int PK AI
DateTimeStamp: Datetime
SelectedValue: Char(2)
UserId: Int

值运行的表结构:

ID: Int PK AI
DateTimeStamp: Datetime
Type: Int
Run: Int

示例数据:[以下以逗号分隔的字符串显示,为简洁起见,由一位用户输入]

e,00,1,t,r,2,4,3,5,7,a,i,w,q,u,o,23,25,24,36,12,e ... < / p>

组将是:

vowels/consonants
even numbers/odd numbers
00
numbers under/over 20
numbers/letters

从上面来看,运行是:

e                (vowels/consonants: vowels)
e                (numbers/letters: letters)
00               (00)
1                (odd/even: odd)
1                (numbers/letters: numbers)
t, r             (vowels/consonants: consonants)
t, r             (numbers/letters: letters)
2, 4             (odd/even: even)
3, 5, 7          (odd/even: odd)
2, 4, 3, 5, 7    (numbers/letters: numbers)
a, i             (vowels/consonants: vowels)
w, q             (vowels/consonants: consonants)
a, i, w, q, u, o (numbers/letters: letters)
1, 2, 4, 3, 5, 7 (under/over 20: under 20)
23, 25           (odd/even: odd)
23, 25, 24, 36   (under/over 20: over 20)
24, 36, 12       (odd/even: even)
u, o, e          (vowels/consonants: vowels)

这将使运行表的条目为

Type: vowels/consonants, run: 1
Type: numbers/letters,   run: 1
Type: 00,                run: 1
Type: odd/even,          run: 1
Type: numbers/letters,   run: 1
Type: odd/even,          run: 2
Type: odd/even,          run: 3
Type: numbers/letters,   run: 5
Type: vowels/consonants, run: 2
Type: vowels/consonants, run: 2
Type: numbers/letters,   run: 6
Type: under/over 20,     run: 6
Type: odd/even,          run: 2
Type: under/over 20,     run: 4
Type: odd/even,          run: 3
Type: vowels/consonants, run: 3

1 个答案:

答案 0 :(得分:1)

编辑根据原始问题的说明进行了更新。

这可能不是最干净的解决方案,但它应该让你开始:

WITH cteClassifications (ID, GroupNo, Type, Description) As
(
    -- Vowels:
    SELECT
        ID,
        1,
        1,
        'Vowels'
    FROM
        RawData
    WHERE
        SelectedValue In ('a', 'e', 'i', 'o', 'u')

    UNION ALL

    -- Consonants:
    SELECT
        ID,
        1,
        2,
        'Consonants'
    FROM
        RawData
    WHERE
        SelectedValue Between 'a' And 'z'
    And
        SelectedValue Not In ('a', 'e', 'i', 'o', 'u')

    UNION ALL

    -- Even numbers:
    SELECT
        ID,
        2,
        1,
        'Even numbers'
    FROM
        RawData
    WHERE
        SelectedValue != '00'
    And
        SelectedValue Not Between 'a' And 'z'
    And
        (TRY_PARSE(SelectedValue As tinyint) & 1) = 0

    UNION ALL

    -- Odd numbers:
    SELECT
        ID,
        2,
        2,
        'Odd numbers'
    FROM
        RawData
    WHERE
        SelectedValue != '00'
    And
        SelectedValue Not Between 'a' And 'z'
    And
        (TRY_PARSE(SelectedValue As tinyint) & 1) = 1

    UNION ALL

    -- "00":
    SELECT
        ID,
        3,
        1,
        '"00"'
    FROM
        RawData
    WHERE
        SelectedValue = '00'

    UNION ALL

    -- Numbers under 20:
    SELECT
        ID,
        4,
        1,
        'Numbers under 20'
    FROM
        RawData
    WHERE
        SelectedValue != '00'
    And
        SelectedValue Not Between 'a' And 'z'
    And
        TRY_PARSE(SelectedValue As tinyint) < 20

    UNION ALL

    -- Numbers over 20:
    SELECT
        ID,
        4,
        2,
        'Numbers over 20'
    FROM
        RawData
    WHERE
        SelectedValue != '00'
    And
        SelectedValue Not Between 'a' And 'z'
    And
        TRY_PARSE(SelectedValue As tinyint) > 20

    UNION ALL

    -- Numbers:
    SELECT
        ID,
        5,
        1,
        'Numbers'
    FROM
        RawData
    WHERE
        SelectedValue != '00'
    And
        SelectedValue Not Between 'a' And 'z'
    And
        TRY_PARSE(SelectedValue As tinyint) Is Not Null

    UNION ALL

    -- Letters:
    SELECT
        ID,
        5,
        2,
        'Letters'
    FROM
        RawData
    WHERE
        SelectedValue Between 'a' And 'z'
),
cteOrderedClassifications (ID, GroupNo, Type, Description, PrevType, RN) As
(
    SELECT
        ID,
        GroupNo,
        Type,
        Description,
        LAG(Type, 1, 0) OVER (PARTITION BY GroupNo ORDER BY ID),
        ROW_NUMBER() OVER (PARTITION BY GroupNo ORDER BY ID)
    FROM
        cteClassifications
),
cteGroupedClassifications (ID, GroupNo, Type, Description, RN, ORN) As
(
    SELECT
        ID,
        GroupNo,
        Type,
        Description,
        RN,
        RN
    FROM
        cteOrderedClassifications As C
    WHERE
        Type != PrevType

    UNION ALL

    SELECT
        C.ID,
        G.GroupNo,
        G.Type,
        G.Description,
        G.RN,
        C.RN
    FROM
        cteGroupedClassifications As G
        INNER JOIN cteOrderedClassifications As C
        ON C.GroupNo = G.GroupNo
        And C.Type = G.Type
        And C.RN = G.ORN + 1
),
cteRuns (ID, GroupNo, Type, Description, RN, Run) As
(
    SELECT
        Min(ID),
        GroupNo,
        Type,
        MAX(Description),
        RN,
        Count(1)
    FROM
        cteGroupedClassifications
    GROUP BY
        GroupNo,
        Type,
        RN
)
SELECT
    ROW_NUMBER() OVER (ORDER BY ID) As ID,
    GroupNo,
    Type,
    Description,
    Run
FROM
    cteRuns
ORDER BY
    ID
;

如果您对查询有效感到满意,可以将最终的SELECT替换为INSERT INTO Runs (ID, Type, Run) SELECT ID, Type, Run FROM cteFinalRuns,以便一次性填充表格。

SQL Fiddle example