【问题标题】:Query to return dynamic number of rows using SQL in SQL Server 2012在 SQL Server 2012 中使用 SQL 查询以返回动态行数
【发布时间】:2017-10-22 06:03:12
【问题描述】:

我有一个独特的要求,以 10 的倍数返回结果行数。例如,如果实际数据行是 3,我必须添加另外 7 个空白行使其成为 10。如果实际数据行是 16,我必须添加另外 4 个空白行使其变为 20,依此类推。

如果不使用过程,是否可以使用 SELECT 语句来实现? 空白行可以只包含 NULL 值或空格或零。

您可以假设任何简单的数据行查询;目的是了解如何以 10 的倍数动态返回行。

例子:

Select EmpName FROM Employees

如果有 3 名员工,我仍应返回 10 行,其余 7 行包含 NULL 值或空白。

我使用的是 SQL Server 2012。

【问题讨论】:

  • 那么,你想要行数,四舍五入到最接近的 10?
  • Edit您的问题并添加一些sample data 和基于该数据的预期输出。 Formatted textno screen shotsedit 您的问题 - 请不要在 cmets 中提供邮政编码或其他信息。
  • SELECT FLOOR((COUNT(*) + 9) / 10) * 10 FROM TABLE; 会给你计数
  • @Manav,我不想要行数。我想要实际的没有。作为 10 的下一个倍数返回的行数。
  • @a_horse_with_no_name,我已经编辑了这个问题。我已经解释过实际查询在这里无关紧要,它可以是任何查询。目的是了解如何添加行,以便返回的行数是 10 的下一个更高倍数。

标签: sql sql-server sql-server-2012


【解决方案1】:

这是如何实现的非常原始的想法:

WITH data(r) AS (
   SELECT 1 r FROM dual
   UNION ALL
   SELECT r+1 r FROM data WHERE r < 10
  ) 
SELECT sd.* 
FROM data d
left join some_data sd on d.r = sd.id 

这是双表结构:

create table dual (dummy varchar(1));
insert into dual values ('x');

小提琴:http://sqlfiddle.com/#!6/5ffcc/4

其中一个可能的选项是:

WITH data(r) AS (
   SELECT 1 r FROM dual
   UNION ALL
   SELECT r+1 r FROM data WHERE r < 10
  ) 
SELECT sd.* 
FROM 
(select r, row_number() over (order by r) rn from data) d
left join ( 
   select id, name, row_number() over (order by id) rn from some_data sd
) sd 
on d.rn = sd.rn 

这种解决方案的明显缺点:

  • 'r' 值生成规则很可能在您的 案子。
  • 在执行查询之前必须知道行数。

但也许它会帮助您找到更好的解决方案。

【讨论】:

    【解决方案2】:

    这是另一种相当简单的处理方法......

    IF OBJECT_ID('tempdb..#TestData', 'U') IS NOT NULL 
    DROP TABLE #TestData;
    
    CREATE TABLE #TestData (
        EmpID INT NOT NULL,
        EmpName VARCHAR(20) NOT NULL
        );
    INSERT #TestData(EmpID, EmpName) VALUES
        (47, 'Bob'),(33, 'Mary'), (88, 'Sue');
    
    -- data as it exists...
    SELECT 
        td.EmpID, 
        td.EmpName
    FROM
        #TestData td;
    
    -- the desired output...
    WITH
        cte_AddRN AS (
            SELECT 
                td.EmpID, 
                td.EmpName,
                RN = ROW_NUMBER() OVER (ORDER BY td.EmpName)
            FROM
                #TestData td
            ),
        cte_TenRows AS (
            SELECT n.RN FROM ( VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9),(10) ) n (RN)
            )
    SELECT 
        ar.EmpID,
        ar.EmpName
    FROM
        cte_TenRows tr
        LEFT JOIN cte_AddRN ar
            ON tr.RN = ar.RN
    ORDER BY
        tr.RN;
    

    结果...

    -- data as it exists...
    EmpID       EmpName
    ----------- --------------------
    47          Bob
    33          Mary
    88          Sue
    
    
    -- the desired output...
    EmpID       EmpName
    ----------- --------------------
    47          Bob
    33          Mary
    88          Sue
    NULL        NULL
    NULL        NULL
    NULL        NULL
    NULL        NULL
    NULL        NULL
    NULL        NULL
    NULL        NULL
    

    【讨论】:

      【解决方案3】:

      基于以上 2 个答案,这是我所做的:

      WITH DATA AS
      (SELECT EmpName FROM Employees),
      DataSummary AS
      (SELECT COUNT(*) AS NumDataRows FROM DATA),
      ReqdDataRows AS
      (SELECT CEILING(NumDataRows/10.0)*10 AS NumRowsReqd FROM DataSummary),
      FillerRows AS 
      (
      SELECT 1 AS SLNO, '00000' AS FillerCol
      UNION ALL
      SELECT 2 AS SLNO, '00000' AS FillerCol
      UNION ALL
      SELECT 3 AS SLNO, '00000' AS FillerCol
      UNION ALL
      SELECT 4 AS SLNO, '00000' AS FillerCol
      UNION ALL
      SELECT 5 AS SLNO, '00000' AS FillerCol
      UNION ALL
      SELECT 6 AS SLNO, '00000' AS FillerCol
      UNION ALL
      SELECT 7 AS SLNO, '00000' AS FillerCol
      UNION ALL
      SELECT 8 AS SLNO, '00000' AS FillerCol
      UNION ALL
      SELECT 9 AS SLNO, '00000' AS FillerCol
      UNION ALL
      SELECT 10 AS SLNO, '00000' AS FillerCol
      )
      SELECT * FROM DATA
      --UNION ALL
      --SELECT CONVERT(VARCHAR(10), NumDataRows) FROM DataSummary
      --UNION ALL
      --SELECT CONVERT(VARCHAR(10), NumRowsReqd) FROM ReqdDataRows
      UNION ALL
      SELECT FillerCol FROM FillerRows
      WHERE (SELECT NumDataRows FROM DataSummary) + SLNO <= (SELECT NumRowsReqd FROM ReqdDataRows)
      

      这给了我想要的输出。这避免了使用ROW_NUMBERORDERing。表 FillerRows 可以使用SELECT * FROM (VALUES...) 进一步简化,第二个和第三个表DataSummaryReqdDataRows 可以合并到一个SELECT 语句中。

      这种方法是循序渐进的方法,易于理解和调试,例如:

      1. 获取实际数据行
      2. 获取数据行数
      3. 计算所需的编号。数据行
      4. 将实际数据行与填充行合并

      欢迎任何关于进一步简化的建议。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-05-22
        • 2014-01-09
        • 1970-01-01
        • 1970-01-01
        • 2020-10-05
        • 1970-01-01
        相关资源
        最近更新 更多