【问题标题】:Top 12 from union queries filtering max 12 rows Ms Sql联合查询中的前 12 名过滤最多 12 行 Ms Sql
【发布时间】:2016-08-08 22:05:58
【问题描述】:

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

【问题讨论】:

  • TOP without ORDER BY 为您提供搜索引擎选择的任何内容。
  • 你快到了。您的查询从 #search 中选择并应用一个订单(您别名为 rn 的列),但随后不使用它。按 rn 排序并将 TOP 12 添加到 select 语句中。

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


【解决方案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 子句。没有这个就没有保证的顺序,使“顶部”成为一个毫无意义的陈述。

【讨论】:

  • 这个我已经在做了。我正在使用 row_number 来获取编号。但我无法获取确切的记录。这是我的情况:
  • 如果有 12 个产品并且还有 10 个类别,我需要它。比它应该选择 6 个产品和 6 个类别。如果是 12 个产品,10 个类别和 5 个制造商,则应该选择 4 个产品,4 个类别和 4 个制造商
  • 这样就可以了。我在这里所做的是结合了三个行号。所以每个表都会有一条记录 1、2、3 等。上面的语句将只返回前 12 条,可以由 1、1、2、2、3、3、4、4、5、5 组成, 6,6 如果只有两个表有记录。
  • 我无法执行此查询。你能帮我吗?这些(1)、(2)、(3)、(4)在编写确切的查询时会有什么?
  • 该部分正在生成虚拟数据,因此我可以演示该技术。在您的示例中,您有一个查询Select ... from #search order by displayorder。将此更改为 SELECT TOP 12 ... FROM #Search ORDER BY rn; 将返回您想要的内容。您在 DisplayOrder 列的正确位置。
【解决方案2】:

如 cmets 中所述,在使用 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

【讨论】:

  • 感谢您的回复。此查询仅获得前 12 行。因此,如果有 12 种产品,那么我只买了那些。
  • 如果有 12 个产品并且还有 10 个类别,我需要它。比它应该选择 6 个产品和 6 个类别。如果是 12 个产品,10 个类别和 5 个标签,那么它应该选择 4 个产品,4 个类别和 4 个标签。
  • 那么您需要发布有关您的表格的详细信息,以便我们可以使用。这是一个很好的起点。 spaghettidba.com/2015/04/24/…
【解决方案3】:

在您的每个查询中,您可以根据当前用于 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 个存在的表,并从其他表中随机组成数字

例如

SELECT TOP 12 DQ.* FROM ('{your query}') DQ ORDER DQ.sorter ASC,newid()

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多