当查询包含通过内部连接的不同顺序时,如何避免在Union All中使用TempTable?

问题描述 投票:0回答:3

我想做的是始终将数量为0的产品发送到已排序的临时表的末尾不丢失当前排序(如我在以下问题How to send Zero Qty Products to the end of a PagedList<Products>?中所述)

我有一个Sorted临时表已填充(按用户选择的字母顺序,价格或较新的产品进行排序,排序基于身份ID):

CREATE TABLE #DisplayOrderTmp 
(
    [Id] int IDENTITY (1, 1) NOT NULL,
    [ProductId] int NOT NULL
)

sorted #DisplayOrderTmp :
+------------+---------------+  
|     id     |  ProductId    |  
+------------+---------------+  
|     1      |     66873     |  // Qty is 0
|     2      |     70735     |  // Qty is not 0
|     3      |     17121     |  // Qty is not 0
|     4      |     48512     |  // Qty is not 0
|     5      |     51213     |  // Qty is 0
+------------+---------------+

我想将此数据传递到网页,但是在此之前,我需要将数量为零的产品发送到此列表的末尾而不丢失当前的排序依据)]

我返回的数据应该是这样(排序不会改变,只有0个数量的产品按其顺序到达列表的末尾):

CREATE TABLE #DisplayOrderTmp4 
(
    [Id] int IDENTITY (1, 1) NOT NULL,
    [ProductId] int NOT NULL
)
+------------+---------------+  
|     id     |  ProductId    |  
+------------+---------------+  
|     1      |     70735     |  
|     2      |     17121     |  
|     3      |     48512     | 
|     4      |     66873     |   
|     5      |     51213     |  
+------------+---------------+ 

P.S:我的产品表,我必须与tmptable进行内部连接以查找产品数量。

    Product Table is like this :
    +------------+---------------+------------------+  
    |     id     |   stockqty    | DisableBuyButton |
    +------------+---------------+------------------+  
    |   17121    |      1        |         0        | 
    |   48512    |      27       |         0        |     
    |   51213    |      0        |         1        |
    |   66873    |      0        |         1        |
    |   70735    |      11       |         0        |
    +------------+---------------+------------------+

到目前为止我尝试过的是:(它正常工作[[有延迟,并且性能问题,我几乎有30k的产品]]

INSERT INTO #DisplayOrderTmp2 ([ProductId]) SELECT p2.ProductId FROM #DisplayOrderTmp p2 with (NOLOCK) // it's already sorted table INNER JOIN Product prd with (NOLOCK) ON p2.ProductId=prd.Id and prd.DisableBuyButton=0 // to find product with qty more than 0 group by p2.ProductId order by min(p2.Id) // to save current ordering INSERT INTO #DisplayOrderTmp3 ([ProductId]) SELECT p2.ProductId FROM #DisplayOrderTmp p2 with (NOLOCK) //it's already sorted table INNER JOIN Product prd with (NOLOCK) ON p2.ProductId=prd.Id and prd.DisableBuyButton=1 // to find product with qty equal to 0 group by p2.ProductId order by min(p2.Id) // to save current ordering INSERT INTO #DisplayOrderTmp4 ([ProductId]) // finally Union All this two data SELECT p2.ProductId FROM #DisplayOrderTmp2 p2 with (NOLOCK) // More than 0 qty products with saved ordering UNION ALL SELECT p2.ProductId FROM #DisplayOrderTmp3 p2 with (NOLOCK) // 0 qty products with saved ordering
有什么方法可以避免在此查询中创建TempTable?发送0第一个模板的数量产品到数据列表的末尾而没有创建其他三个tempTable,而不丢失基于

Identity ID

的当前顺序。我的查询出现性能问题。我不得不再说一遍,该临时表具有一个标识插入ID列,并且它是基于排序的排序类型,用户已将其传递给存储过程。谢谢大家:)
sql-server stored-procedures nopcommerce sqlperformance
3个回答
1
投票
SELECT p2.ProductId FROM #DisplayOrderTmp p2 JOIN Product prd ON p2.ProductId=prd.Id ORDER BY prd.DisableBuyButton, p2.id;

DisableBuyButton = 0-qnt> 0DisableBuyButton = 1-qnt = 0


1
投票
IIFCASE可用于优先排序。

SELECT tmp.ProductId FROM #DisplayOrderTmp tmp JOIN Product prd ON prd.Id = tmp.ProductId AND prd.DisableBuyButton IN (0,1) ORDER BY IIF(prd.DisableBuyButton=0,1,2), tmp.id;


1
投票
CREATE TABLE #DisplayOrderTmp ( [Id] int NOT NULL, [ProductId] int NOT NULL ,PRIMARY KEY CLUSTERED(Id) );

有了该索引,您应该能够使用UNION ALL查询以合理的效率在不使用其他临时表的情况下获得结果,假设ProductID是Product表的主键:

WITH products AS (
    SELECT p2.Id, p2.ProductId, prd.stockqty, 1 AS seq
    FROM #DisplayOrderTmp p2
    JOIN Product prd
          ON p2.ProductId=prd.Id
    WHERE prd.stockqty > 0
    UNION ALL
    SELECT p2.Id, p2.ProductId, prd.stockqty, 2 AS seq
    FROM #DisplayOrderTmp p2
    JOIN Product prd
          ON p2.ProductId=prd.Id
    WHERE prd.stockqty = 0
)
SELECT ProductId
FROM products
ORDER BY seq, Id;

您在评论中提到您最终希望获得分页结果。可以在T-SQL中通过如下向OFFSET子句添加FETCHORDER BY来完成。但是,请注意,在较大的结果集上进行分页时,对查询结果的进一步查询将逐渐变慢。

WITH products AS (
    SELECT p2.Id, p2.ProductId, prd.stockqty, 1 AS seq
    FROM #DisplayOrderTmp p2
    JOIN Product prd
          ON p2.ProductId=prd.Id
    WHERE prd.stockqty > 0
    UNION ALL
    SELECT p2.Id, p2.ProductId, prd.stockqty, 2 AS seq
    FROM #DisplayOrderTmp p2
    JOIN Product prd
          ON p2.ProductId=prd.Id
    WHERE prd.stockqty = 0
)
SELECT ProductId
FROM products
ORDER BY seq, Id
OFFSET @PageSize * (@PageNumber - 1) ROWS
FETCH NEXT @PageSize ROWS ONLY;
© www.soinside.com 2019 - 2024. All rights reserved.