来自联合查询的前12个过滤最多12行Ms Sql

时间:2016-08-08 13:10:57

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

我面临的问题是,我需要来自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

3 个答案:

答案 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()