【问题标题】:can i iterate through a table in sql without having an id column?我可以在没有 id 列的情况下遍历 sql 中的表吗?
【发布时间】:2018-10-17 04:27:58
【问题描述】:

假设我有一个包含两列(例如季度和年份)的表,我想根据这两列的值创建第三列。有没有办法在没有或创建标识列的情况下使用 while 循环迭代表?

举个例子,假设我有这些行:

Quarter    Year    Datetimes  
---------- ------  --------------  
1          2018    null  
2          2018    null  
3          2018    null  

我想更新第 3 列并使它:

Quarter    Year    Datetimes  
---------- ------  --------------  
1          2018    2018-03-31 00:00:00.000  
2          2018    2018-06-30 00:00:00.000  
3          2018    2018-09-30 00:00:00.000  

我知道如何进行转换,公式是这样的:

DATEADD(YEAR, @theYear - 1900, DATEADD(QQ, @TheQuarter, -1)).   

问题是我想更新表格,这意味着我想添加新信息,而不仅仅是显示第三列的输出。

【问题讨论】:

  • 为什么要第三列? (当数据已经存在时,在两个已经存在的列中。)顺便说一句,SQL Server 有计算列...
  • 为什么要迭代?你想执行什么样的计算? SQL Server 有许多排名函数,如 ROW_NUMBER()、RANK、DENSE_RANK、NTILE。您也可以使用 OVER 子句计算运行总和、平均值等,例如 SUM(someValue) OVER (Partition by YEAR,Month) 将返回每年和每月的每月总计
  • 如果你想要一个每月的总计,你可以写例如SUM(someValue) OVER (Partition by YEAR,Month ORDER BY Year,Month,Day ROWS UNBOUNDED PRECEDING)
  • 如果你想计算一年和一个月的结束日期,你可以写select eomonth(datefromparts(YearColumn,MonthColumn,1))。你不需要循环。你想做什么?

标签: sql sql-server loops while-loop


【解决方案1】:

嗯,是的,您可以使用没有id 列的游标遍历表。

但出于以下几个原因,这是一个非常糟糕的主意:

  1. 一般情况下,您应该避免使用光标。
  2. 您的表都应该已定义主 ID。
  3. 您可以使用基于集合的查询来做您想做的事情。

【讨论】:

    【解决方案2】:

    CURSOR 对象专门设计用于遍历由SELECT 确定的任何行集。您的SELECT 可以像您想要的那样复杂,并且不需要行是唯一的。

    基本语法如下例:

    IF OBJECT_ID('tempdb..#Dates') IS NOT NULL
        DROP TABLE #Dates
    
    CREATE TABLE #Dates (
        Month INT,
        Year INT)
    
    INSERT INTO #Dates (
        Month,
        Year)
    VALUES
        (1, 2018),
        (5, 2018),
        (10, 2020),
        (10, 2020) -- Repeated value
    
    DECLARE @c_Month INT
    DECLARE @c_Year INT
    
    DECLARE DateCursor CURSOR FOR
        SELECT
            D.Month,
            D.Year
        FROM
            #Dates AS D
        ORDER BY
            D.Year,
            D.Month
    
    OPEN DateCursor
    
    FETCH NEXT FROM DateCursor INTO 
        @c_Month,
        @c_Year
    
    WHILE @@FETCH_STATUS = 0
    BEGIN
    
        SELECT
            Month = @c_Month,
            Year = @c_Year,
            CalculatedColumn = DATEFROMPARTS(@c_Year, @c_Month, 1)
    
        FETCH NEXT FROM DateCursor INTO 
            @c_Month,
            @c_Year
    
    END
    
    CLOSE DateCursor
    DEALLOCATE DateCursor
    
    /*
    Results:
    
        Month       Year        CalculatedColumn
        ----------- ----------- ----------------
        1           2018        2018-01-01
    
        Month       Year        CalculatedColumn
        ----------- ----------- ----------------
        5           2018        2018-05-01
    
        Month       Year        CalculatedColumn
        ----------- ----------- ----------------
        10          2020        2020-10-01
    
        Month       Year        CalculatedColumn
        ----------- ----------- ----------------
        10          2020        2020-10-01
    
    */
    

    话虽如此,请尽可能避免使用游标,因为关系数据库的设计和优化可与集合一起使用。光标应该是你最后的手段。

    编辑:你根本不需要光标:

    UPDATE T SET
        YourColumn = DATEADD(YEAR, T.Year - 1900, DATEADD(QQ, T.Quarter, -1))
    FROM
        YourTable AS T
    

    【讨论】:

    • 我认为这可行,但我想在 while 循环内将第三列从 null 更新为每行的计算值
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-07-25
    • 1970-01-01
    • 2013-05-31
    • 2010-12-07
    • 2020-05-30
    • 1970-01-01
    • 2023-04-08
    相关资源
    最近更新 更多