SQL-pad结果有额外的行

时间:2013-06-14 05:20:57

标签: sql sql-server

我有一组记录,其中包含“商店”列。我需要基本上将结果集拆分为13个记录的组,创建空行以填充每个商店以包含13行。 为简单起见,我想说我需要4组记录。

示例,给出下表:

-----------------
Store      Name
-----------------
A          John
A          Bill
B          Sam
C          James
C          Tim
C          Chris
D          Simon
D          Phil

我需要结果如下:

-----------------
Store      Name
-----------------
A          John
A          Bill
A
B          Sam
B
B
C          James
C          Tim
C          Chris
D          Simon
D          Phil
D

纯SQL可以实现这一点吗?每个商店永远不会超过3行。 SQL Fiddle

5 个答案:

答案 0 :(得分:9)

试试这个 -

<强> DDL:

SET STATISTICS IO ON;

IF OBJECT_ID (N'tempdb.dbo.#temp') IS NOT NULL
   DROP TABLE #temp

CREATE TABLE #temp
(
      Store CHAR(1)
    , Name VARCHAR(10)
)

INSERT INTO #temp (Store, Name)
VALUES 
    ('A', 'John'),  ('A', 'Bill'),
    ('B', 'Sam'),   ('C', 'James'),
    ('C', 'Tim'),   ('C', 'Chris'),
    ('D', 'Simon'), ('D', 'Phil')

<强>查询:

DevArt#1:

;WITH cte AS 
(
    SELECT 
          Store
        , Name
        , rn = ROW_NUMBER() OVER (PARTITION BY Store ORDER BY (SELECT 1)) 
    FROM #temp
)
SELECT t.Store, Name = ISNULL(t3.Name, '')
FROM (
    SELECT DISTINCT Store 
    FROM cte
) t
CROSS JOIN (SELECT rn = 1 UNION ALL SELECT 2 UNION ALL SELECT 3) t2
LEFT JOIN cte t3 ON t2.rn = t3.rn AND t.Store = t3.Store

DevArt#2:

SELECT t2.Store, Name = ISNULL(t3.Name, '')
FROM (
    SELECT *
    FROM (
        SELECT Store, r = COUNT(1)
        FROM #temp
        GROUP BY Store
    ) t
    CROSS APPLY (
        VALUES (r), (r+1), (r+2)
    ) t2 (x)
) t2
LEFT JOIN #temp t3 ON t2.Store = t3.Store AND t2.x = t2.r
WHERE t2.x < 4

Alexander Fedorenko:

;WITH cte AS
(
    SELECT DISTINCT Store
    FROM #temp
)  
SELECT o.Store, o.name
FROM cte s 
CROSS APPLY (
    SELECT TOP 3 x.Store, x.name
    FROM (
        SELECT s2.Store, s2.name
        FROM #temp s2
        WHERE s.Store = s2.Store
        UNION ALL
        SELECT s.Store, ''
        UNION ALL
        SELECT s.Store, ''
    ) x
) o

<强> ErikE:

SELECT Store, Name
FROM (
   SELECT 
          x.Store
        , x.Name
        , s = ROW_NUMBER() OVER (PARTITION BY x.Store ORDER BY x.s)
   FROM #temp t
   CROSS APPLY (
        VALUES 
            (Store, Name, 0), 
            (Store, '', 1), 
            (Store, '', 1)
   ) x (Store, Name, S)
) z
WHERE s <= 3
ORDER BY Store

<强> AmitSingh:

SELECT t.Store, Name = COALESCE(
    (
        SELECT name
        FROM (
            SELECT 
                  row1 = ROW_NUMBER() OVER (PARTITION BY Store ORDER BY Store) 
                , *
            FROM #temp
        ) c
        WHERE t.[row] = c.row1
            AND t.Store = c.Store
    )
    , '') 
FROM
(
    SELECT
          [Row] = ROW_NUMBER() OVER (PARTITION BY a.Store ORDER BY a.Store) 
        , a.Store
    FROM (
        SELECT Store
        FROM #temp
        GROUP BY Store
    ) a
    , (
        SELECT TOP 3 Store
        FROM #temp
    ) b
) t

Andriy M#1:

;WITH ranked AS 
(
     SELECT
            Store
          , Name
          , rnk = ROW_NUMBER() OVER (PARTITION BY Store ORDER BY 1/0)
     FROM #temp
)
, pivoted AS 
(
     SELECT
            Store
          , [1] = ISNULL([1], '')
          , [2] = ISNULL([2], '')
          , [3] = ISNULL([3], '')
     FROM ranked
     PIVOT (
          MAX(Name) 
          FOR rnk IN ([1], [2], [3])
     ) p
)
, unpivoted AS 
(
     SELECT
            Store
          , Name
     FROM pivoted
     UNPIVOT (
          Name FOR rnk IN ([1], [2], [3])
     ) u
)
SELECT *
FROM unpivoted

Andriy M#2:

;WITH ranked AS 
(
     SELECT
            Store
          , Name
          , rnk = ROW_NUMBER() OVER (PARTITION BY Store ORDER BY 1/0)
     FROM #temp
)
, padded AS 
(
     SELECT
            Store
          , Name
     FROM ranked
     PIVOT (
          MAX(Name) 
          FOR rnk IN ([1], [2], [3])
     ) p
     CROSS APPLY (
          VALUES
               (ISNULL([1], '')),
               (ISNULL([2], '')),
               (ISNULL([3], ''))
     ) x (Name)
)
SELECT *
FROM padded

<强>输出:

Store Name
----- ----------
A     John
A     Bill
A     
B     Sam
B     
B     
C     James
C     Tim
C     Chris
D     Simon
D     Phil
D     

<强>统计:

    Query Presenter  Scans  Logical Reads
-------------------  -----  -------------
          DevArt #1    3     41
          DevArt #2    2      9
Alexander Fedorenko    4      5
              ErikE    1      1
          AmitSingh   22     25
        Andriy M #1    1      1
        Andriy M #2    1      1

查询费用

Query cost

扩展统计信息:

ExStat

执行统计信息:

ExecStat

查询计划(来自dbForge Studio for MS SQL):

Query plan

答案 1 :(得分:4)

Select t.store_id,Coalesce((Select Name from (
 Select row_Number() Over(Partition by store_id order by store_id) as row1, * from stores)c
 where t.row=c.row1 and t.store_id=c.store_id),'') as cfgg
from
 (Select row_Number() Over(Partition by a.store_id order by a.store_id) as row, 
 a.store_id from 
 (Select store_id from stores group by store_id) a ,(Select top 3 store_id from stores)b
 ) t

SQL Fiddle Demo

答案 2 :(得分:4)

APPLY运算符的另一个选项

 ;WITH cte AS
 (
  SELECT store_id
  FROM stores
  GROUP BY store_id  
  )  
  SELECT o.store_id, o.name
  FROM cte s CROSS APPLY (
                          SELECT TOP 3 x.store_id, x.name
                          FROM (
                                SELECT s2.store_id, s2.name
                                FROM stores s2
                                WHERE s.store_id = s2.store_id
                                UNION ALL
                                SELECT s.store_id, ''
                                UNION ALL
                                SELECT s.store_id, ''                                 
                                ) x
                          ) o

SQLFiddle上的演示

答案 3 :(得分:4)

这是一个有效的查询(SQL Server 2008及更高版本,可以在2005年修复工作):

SELECT Store, Name
FROM (
   SELECT
      X.Store, X.Name, R = Row_Number() OVER (PARTITION BY X.Store ORDER BY X.S)
   FROM
      @temp T
      CROSS APPLY (VALUES
         (Store, Name, 0), (Store, '', 1), (Store, '', 1)
      ) X (Store, Name, S)
) Z
WHERE R <= 3
ORDER BY Store
;

根据SET STATISTICS IO ON;,这里有性能统计数据(在这么低的行数下,所有CPU的CPU都可以忽略不计,或许更多行可以帮助确定最佳表现者):

    Query Presenter  Scans  Logical Reads
-------------------  -----  -------------
              ErikE    1      1
Alexander Fedorenko    4      5
             Devart    3     41
          AmitSingh   22     25

我的查询不保留每个商店的名称的“原始”排序,但是是一个缺陷,因为在关系数据库表中没有排序的概念。如果要保留特定序列,必须提供要排序的列。

答案 4 :(得分:2)

又一个选项,这次using PIVOT and UNPIVOT

WITH ranked AS (
  SELECT
    store_id,
    name,
    rnk = ROW_NUMBER() OVER (PARTITION BY store_id ORDER BY 1/0)
  FROM stores
),
pivoted AS (
  SELECT
    store_id,
    [1] = ISNULL([1], ''),
    [2] = ISNULL([2], ''),
    [3] = ISNULL([3], '')
  FROM ranked
  PIVOT (
    MAX(name) FOR rnk IN ([1], [2], [3])
  ) p
),
unpivoted AS (
  SELECT
    store_id,
    name
  FROM pivoted
  UNPIVOT (
    name FOR rnk IN ([1], [2], [3])
  ) u
)
SELECT *
FROM unpivoted
;

使用的SQL小提琴演示:http://sqlfiddle.com/#!3/354df/39

请注意,上述查询中的UNPIVOT步骤必须在与PIVOT操作不同的SELECT中完成。这是因为UNPIVOT不会生成IN列列表中列出的列包含NULL的行。但是,您可以使用等效技术(如CROSS APPLY)替换UNPIVOT,从而将unpivoting移动到进行旋转的同一子查询中:

WITH ranked AS (
  SELECT
    store_id,
    name,
    rnk = ROW_NUMBER() OVER (PARTITION BY store_id ORDER BY 1/0)
  FROM stores
),
padded AS (
  SELECT
    store_id,
    name
  FROM ranked
  PIVOT (
    MAX(name) FOR rnk IN ([1], [2], [3])
  ) p
  CROSS APPLY (
    VALUES
      (ISNULL([1], '')),
      (ISNULL([2], '')),
      (ISNULL([3], ''))
  ) x (name)
)
SELECT *
FROM padded
;

修改版本的SQL小提琴演示:http://sqlfiddle.com/#!3/354df/40