我面临的问题是,我需要来自3个表联合数据的12个最大行。但是,如果任何表没有固定的行,那么应考虑剩余的行。
例如:我有3张桌子 产品 类别 制造商
案例1:如果每个都有10行,那么我们应该从每个表中选择4行。 案例2:如果产品表有3行和类别,则制造商有5行 每个,应该从产品中选择3个,从类别或制造商中选择5个。 案例3:所有行都少于4行,显示可用的行数。
请帮助我实现这个目标。我发布了我迄今为止创建的存储过程。
Create PROCEDURE [dbo].[GetRowsfromtables]
@SearchTerms nvarchar(150)
AS
BEGIN
create table #search (id int identity ,ids int, productname nvarchar(200), categoryname nvarchar(200), tagname nvarchar(200), SeName nvarchar(200), displayorder int)
insert into #search
Select Top 12 p.Id as ids, p.name as productname, '' as categoryname, '' as tagname, '' as SeName, 0 as displayorder from Product p where p.Published = 1 and p.Deleted = 0 and name like '%' + @SearchTerms + '%'
union
Select Top 12 c.id as ids, '' as productname, c.name as categoryname, '' as tagname, '' as SeName , 1 as displayorder from Category c where c.Published = 1 and c.Deleted = 0 and Name like '%' + @SearchTerms + '%'
union
Select Top 12 t.id as ids, '' as productname, '' as categoryname, t.Name as tagname, '' as SeName, 2 as displayorder
from Manufacturer
where Name like '%' + @SearchTerms + '%'
Select id, ids,productname,categoryname, tagname, SeName, tagpcount,tagproductid,
'' as ThumbnailImage, displayorder, (Select count(*) from #search where displayorder = 0) as ptotal,
(Select count(*) from #search where displayorder = 1) as ctotal,
(Select count(*) from #search where displayorder = 2) as tagtotal,
row_number() over(partition by displayorder order by id ) as rn
from #search
order by displayorder
drop table #search
END
答案 0 :(得分:1)
您可以使用窗口函数ROW_NUMBER对联合中的记录进行排序。然后按行号排序结果:
/* Generate 13 sample records:
* Product (4)
* Category (6)
* Manufacturer (3)
*/
WITH Product AS
(
-- Sample product records.
SELECT
Id
FROM
(
VALUES
(1),
(2),
(3),
(4)
) AS x(Id)
),
Category AS
(
-- Sample category records.
SELECT
Id
FROM
(
VALUES
(1),
(2),
(3),
(4),
(5),
(6)
) AS x(Id)
),
Manufacturer AS
(
-- Sample manufacturer records.
SELECT
Id
FROM
(
VALUES
(1),
(2),
(3)
) AS x(Id)
)
SELECT TOP 12
*
FROM
(
SELECT
ROW_NUMBER() OVER (ORDER BY ID) AS rn,
'P' AS Tbl,
Id
FROM
Product
UNION ALL
SELECT
ROW_NUMBER() OVER (ORDER BY ID) AS rn,
'C' AS Tbl,
Id
FROM
Category
UNION ALL
SELECT
ROW_NUMBER() OVER (ORDER BY ID) AS rn,
'M' AS Tbl,
Id
FROM
Manufacturer
) AS u
ORDER BY
rn
;
order by将首先返回编号为1的所有记录,然后返回2,依此类推。这将提供源数据允许的均匀混合。
修改强> 从每个子查询中删除了TOP。我试图通过限制它必须应用行号的记录数来帮助SQL。但ROW_NUMBER应用于顶部之前,这使得这有点毫无意义。我的子查询也缺少ORDER BY子句。如果没有这个,就没有保证订单,使得" top"一个毫无意义的陈述。
答案 1 :(得分:1)
如评论中所述,您在使用TOP时需要使用ORDER BY,否则您将无法确定将获得哪些顶行。此处也不需要创建临时表,因此您可以从中进行选择然后删除它。我在原件周围添加了一些(很好的)白色空间,因此更容易看到并保持在路上。这样的事情应该与你追求的非常接近。
有一件重要的事情是,您的原始查询中定义了几个列,这些列不在您定义的临时表中。不知道你想要做什么,所以我就把它们留在那里。
Select top 12 id
, ids
, productname
, categoryname
, tagname
, SeName
, tagpcount
, tagproductid
, '' as ThumbnailImage
, displayorder
, ptotal = sum(case when displayorder = 0 then 1 else 0 end)
, ctotal = sum(case when displayorder = 1 then 1 else 0 end)
, tagtotal = sum(case when displayorder = 2 then 1 else 0 end)
, row_number() over(partition by displayorder order by id ) as rn
from
(
Select Top 12 p.Id as ids
, p.name as productname
, '' as categoryname
, '' as tagname
, '' as SeName
, 0 as displayorder
from Product p
where p.Published = 1
and p.Deleted = 0
and name like '%' + @SearchTerms + '%'
ORDER BY p.name --or whatever column
union ALL
Select Top 12 c.id as ids
, '' as productname
, c.name as categoryname
, '' as tagname
, '' as SeName
, 1 as displayorder
from Category c
where c.Published = 1
and c.Deleted = 0
and Name like '%' + @SearchTerms + '%'
ORDER BY c.name --or whatever column
union ALL
Select Top 12 t.id as ids
, '' as productname
, '' as categoryname
, t.Name as tagname
, '' as SeName
, 2 as displayorder
from Manufacturer
where Name like '%' + @SearchTerms + '%'
ORDER BY t.Name --or whatever column
) x
group by id
, ids
, productname
, categoryname
, tagname
, SeName
, tagpcount
, tagproductid
, displayorder
order by displayorder
答案 2 :(得分:0)
在每个查询中,您可以根据当前用于TOP n的排序顺序确定row_number() - 然后根据row_number执行CASE
CASE WHEN row_number() OVER(...) <= 4 THEN 1 ELSE 2 END AS sorter
在每种情况下删除TOP n。
完成3个表的联合后,将UNION中的TOP 12作为子查询,并按分类器ASC,NEWID()进行排序。这样你就可以保证它们存在的任何4个表,以及来自其他表的randoms来组成数字
e.g。
SELECT TOP 12 DQ。* FROM('{your query}')DQ ORDER DQ.sorter ASC,newid()