在SQL中插入空行数

时间:2016-10-15 20:20:55

标签: sql sql-server sql-server-2008

使用SQL查询,我需要在结果中包含空白行,以使每组(family_id)等于4行

SELECT   
    ROW_NUMBER() OVER(PARTITION BY family_id ORDER BY family_id) AS rowNum,
    full_name as name, family_id
FROM
    tbl_person

像这样:

original result

,结果将是

enter image description here

5 个答案:

答案 0 :(得分:2)

只需定义第二个查询,构建您需要的空行并将它们组合在一起。

SELECT ROW_NUMBER() OVER(PARTITION BY family_id ORDER BY family_id) AS rowNum,
    full_name as name,
    family_id
FROM tbl_person

UNION ALL

SELECT n.N AS rowNum,
    NULL AS name,
    p.family_id
FROM (SELECT family_id, COUNT(*) family_count FROM tbl_person group by family_id) p
INNER JOIN (
    SELECT 1 AS N
    UNION ALL SELECT 2
    UNION ALL SELECT 3
    UNION ALL SELECT 4
    ) n
    ON n.n > p.family_count
ORDER BY family_id,
    rowNum,
    name;

答案 1 :(得分:2)

如果您使用计数表(因为它只能是4个数字,它可以是内联的)并且您将它们交叉应用于所有family_ids,您将获得每个family_id的数字1到4的记录。然后在nr和family_id上保持连接,结果将为每个id包含4行,其中只填充现有行的数据。 (为防止双重引用,您可以在主表上使用cte获取两个id并执行左连接,但您也可以直接在主表上执行该组)

app.UseExceptionHandler(errorApp =>
{
    errorApp.Run(async context =>
    {
        context.Response.StatusCode = 500; // or another Status
        context.Response.ContentType = "application/json";

        var error = context.Features.Get<IExceptionHandlerFeature>();
        if (error != null)
        {
            var ex = error.Error;

            await context.Response.WriteAsync(new ErrorDto()
            {
                Code = 1, //<your custom code based on Exception Type>,
                Message = ex.Message // or your custom message
                // … other custom data
            }.ToString(), Encoding.UTF8);
        }
    });
});

<小时/> 的 修改 由于您需要更多行,因此使用某种计数表更容易(之后创建和更改)。我最喜欢的一个是使用现有的sys表:

with p as
(
    SELECT   *,ROW_NUMBER() OVER(PARTITION BY family_id ORDER BY family_id) AS rowNum  
    FROM tbl_person
)
select nr as row_num, full_name as name, f.family_id
from (values(1),(2),(3),(4)) as nrs(nr) --inline tally table
cross apply (select family_id from p group by family_id) f --group by family id to get all existing id's
left join  p on p.rowNum = nr and f.family_id = p.family_id

答案 2 :(得分:2)

使用递归CTE将空行添加到每个组的最后一行:

with Q as(
 SELECT full_name as name, age, family_id,
        ROW_NUMBER() OVER(PARTITION BY family_id ORDER BY family_id) AS rowNum,
        count(1) over(partition by family_id) cnt
   FROM tbl_person
 union all
  select NULL,NULL,family_id, Q.rowNum+1, Q.rowNum+1
    from Q
   where Q.cnt=Q.rowNum and Q.rowNum < 4
)
select * from Q
 order by family_id, rowNum

答案 3 :(得分:1)

我会使用cte Tally表根据你唯一的family_id值构建一个骨架,并使用cte Results表,它可以根据tally number =行号保持连接到骨架。

Declare @family_row_count int = 14;

-- Tally Table CTE script (SQL 2005+ only)
-- You can use this to create many different numbers of rows... for example:
-- You could use a 3 way cross join (t3 x, t3 y, t3 z) instead of just 2 way to generate a different number of rows.
-- The # of rows this would generate for each is noted in the X3 comment column below.
-- For most common usage, I find t3 or t4 to be enough, so that is what is coded here.
-- If you use t3 in ‘Tally’, you can delete t4 and t5.


; WITH
    -- Tally table Gen            Tally Rows:     X2                X3
t1 AS (SELECT 1 N UNION ALL SELECT 1 N),    -- 4            ,    8
t2 AS (SELECT 1 N FROM t1 x, t1 y),            -- 16            ,    64
t3 AS (SELECT 1 N FROM t2 x, t2 y),            -- 256            ,    4096
t4 AS (SELECT 1 N FROM t3 x, t3 y),            -- 65536        ,    16,777,216
t5 AS (SELECT 1 N FROM t4 x, t4 y),            -- 4,294,967,296,    A lot
Tally AS (SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) N
          FROM t3 x, t3 y) -- Change the t3's to one of the other numbers above for more/less rows 

, cte_Skeleton
as (
    select
         tally.N as [row_number]
         , family.family_id
    from Tally tally
    cross join ( select family_id from tbl_person group by family_id ) family
    where tally.N <= @family_row_count
)

, cte_person
as
(
    SELECT
        ROW_NUMBER() OVER(PARTITION BY family_id ORDER BY family_id) AS rowNum
        , full_name as name
        , family_id
    FROM tbl_person
)

select
      skeleton.[row_number] as [rowNum]
    , person.name
    , person.age
    , skeleton.family_id

from cte_Skeleton skeleton

left join cte_person person
    on person.family_id = skeleton.family_id
    and person.rownum = skeleton.[row_number]

注意,因为您已经首先定义了骨架并且正在加入它,即使family_id包含超过14个人,也只有前14个将具有要在连接中匹配的骨架行。

答案 4 :(得分:0)

适用于任何人的一般解决方案 (SQLFiddle - http://sqlfiddle.com/#!3/00677/25):

WITH 

maxRow AS (
  SELECT TOP 1 COUNT(*) maxRow FROM tbl_person GROUP BY family_id ORDER BY 1 DESC 
),

rn AS (
  SELECT 1 as rowNum
  UNION ALL
  SELECT rowNum + 1
  FROM rn 
  WHERE rowNum < (SELECT * FROM maxRow)
),

rnFi AS (
SELECT 
  * 
FROM 
  rn,
  (SELECT DISTINCT family_id FROM tbl_person) fi
)

SELECT
  rnFi.rowNum,
  rnFi.family_id,
  t.name
FROM
  rnFi
LEFT JOIN
  (SELECT   
    ROW_NUMBER() OVER(PARTITION BY family_id ORDER BY family_id) AS rowNum,
    family_id,
    name
  FROM
    tbl_person) t ON rnFi.family_id = t.family_id AND rnFi.rowNum = t.rowNum
ORDER BY
  2, 1
;