使用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
像这样:
,结果将是
答案 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
;