gpt4 book ai didi

sql-server - CTE 到底如何发挥作用?

转载 作者:行者123 更新时间:2023-12-02 10:19:52 26 4
gpt4 key购买 nike

我遇到了this CTE solution for concatenating row elements我认为这太棒了,我意识到 CTE 有多么强大。

但是,为了有效地使用这样的工具,我需要知道它如何在内部工作以构建心理图像,这对于像我这样的初学者在不同场景中使用它至关重要。

所以我尝试慢动作上述片段的过程,这是代码

USE [NORTHWIND]
GO
/****** Object: Table [dbo].[Products2] Script Date: 10/18/2011 08:55:07 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
IF OBJECT_ID('Products2','U') IS NOT NULL DROP TABLE [Products2]
CREATE TABLE [dbo].[Products2](
[ProductID] [int] IDENTITY(1,1) NOT NULL,
[ProductName] [nvarchar](40) NOT NULL,
[SupplierID] [int] NULL,
[CategoryID] [int] NULL,
[QuantityPerUnit] [nvarchar](20) NULL,
[UnitPrice] [money] NULL,
[UnitsInStock] [smallint] NULL,
[UnitsOnOrder] [smallint] NULL,
[ReorderLevel] [smallint] NULL,
[Discontinued] [bit] NOT NULL
) ON [PRIMARY]
GO
SET IDENTITY_INSERT [dbo].[Products2] ON
INSERT [dbo].[Products2] ([ProductID], [ProductName], [SupplierID], [CategoryID], [QuantityPerUnit], [UnitPrice], [UnitsInStock], [UnitsOnOrder], [ReorderLevel], [Discontinued]) VALUES (1, N'vcbcbvcbvc', 1, 4, N'10 boxes x 20 bags', 18.0000, 39, 0, 10, 0)
INSERT [dbo].[Products2] ([ProductID], [ProductName], [SupplierID], [CategoryID], [QuantityPerUnit], [UnitPrice], [UnitsInStock], [UnitsOnOrder], [ReorderLevel], [Discontinued]) VALUES (2, N'Changassad', 1, 1, N'24 - 12 oz bottles', 19.0000, 17, 40, 25, 0)
INSERT [dbo].[Products2] ([ProductID], [ProductName], [SupplierID], [CategoryID], [QuantityPerUnit], [UnitPrice], [UnitsInStock], [UnitsOnOrder], [ReorderLevel], [Discontinued]) VALUES (3, N'Aniseed Syrup', 1, 2, N'12 - 550 ml bottles', 10.0000, 13, 70, 25, 0)
INSERT [dbo].[Products2] ([ProductID], [ProductName], [SupplierID], [CategoryID], [QuantityPerUnit], [UnitPrice], [UnitsInStock], [UnitsOnOrder], [ReorderLevel], [Discontinued]) VALUES (4, N'Chef Anton''s Cajun Seasoning', 2, 2, N'48 - 6 oz jars', 22.0000, 53, 0, 0, 0)
INSERT [dbo].[Products2] ([ProductID], [ProductName], [SupplierID], [CategoryID], [QuantityPerUnit], [UnitPrice], [UnitsInStock], [UnitsOnOrder], [ReorderLevel], [Discontinued]) VALUES (5, N'Chef Anton''s Gumbo Mix', 10, 2, N'36 boxes', 21.3500, 0, 0, 0, 1)
SET IDENTITY_INSERT [dbo].[Products2] OFF
GO
IF OBJECT_ID('DELAY_EXEC','FN') IS NOT NULL DROP FUNCTION DELAY_EXEC
GO
CREATE FUNCTION DELAY_EXEC() RETURNS DATETIME
AS
BEGIN
DECLARE @I INT=0
WHILE @I<99999
BEGIN
SELECT @I+=1
END
RETURN GETDATE()
END
GO

WITH CTE (EXEC_TIME, CategoryID, product_list, product_name, length)
AS (SELECT dbo.DELAY_EXEC(),
CategoryID,
CAST('' AS VARCHAR(8000)),
CAST('' AS VARCHAR(8000)),
0
FROM Northwind..Products2
GROUP BY CategoryID
UNION ALL
SELECT dbo.DELAY_EXEC(),
p.CategoryID,
CAST(product_list + CASE
WHEN length = 0 THEN ''
ELSE ', '
END + ProductName AS VARCHAR(8000)),
CAST(ProductName AS VARCHAR(8000)),
length + 1
FROM CTE c
INNER JOIN Northwind..Products2 p
ON c.CategoryID = p.CategoryID
WHERE p.ProductName > c.product_name)
SELECT *
FROM CTE
ORDER BY EXEC_TIME

--SELECT CategoryId, product_list
-- FROM ( SELECT CategoryId, product_list,
-- RANK() OVER ( PARTITION BY CategoryId ORDER BY length DESC )
-- FROM CTE ) D ( CategoryId, product_list, rank )
-- WHERE rank = 1 ;

注释 block 是串联问题所需的输出,但这不是这里的问题。

我添加了一列 EXEC_TIME 以了解首先添加哪一行。由于两个原因,输出对我来说看起来不正确

  1. 我认为由于条件 p.ProductName > c.product_name 而存在冗余数据,换句话说,CTE 的第一部分中的空行始终小于中的值Product2 表,因此每次运行时,它都应该再次带来一组已添加的新行。这有什么意义吗?

  2. 数据的层次结构真的很奇怪,最后一项应该是最长的,看看最后一项是什么?具有 length=1 的项目?

有高手来帮忙吗?提前致谢。

示例结果

EXEC_TIME               CategoryID  product_list                                                        product_name                      length
----------------------- ----------- ------------------------------------------------------------------- --------------------------------- -----------
2011-10-18 12:46:14.930 1 0
2011-10-18 12:46:14.990 2 0
2011-10-18 12:46:15.050 4 0
2011-10-18 12:46:15.107 4 vcbcbvcbvc vcbcbvcbvc 1
2011-10-18 12:46:15.167 2 Aniseed Syrup Aniseed Syrup 1
2011-10-18 12:46:15.223 2 Chef Anton's Cajun Seasoning Chef Anton's Cajun Seasoning 1
2011-10-18 12:46:15.280 2 Chef Anton's Gumbo Mix Chef Anton's Gumbo Mix 1
2011-10-18 12:46:15.340 2 Chef Anton's Cajun Seasoning, Chef Anton's Gumbo Mix Chef Anton's Gumbo Mix 2
2011-10-18 12:46:15.400 2 Aniseed Syrup, Chef Anton's Cajun Seasoning Chef Anton's Cajun Seasoning 2
2011-10-18 12:46:15.463 2 Aniseed Syrup, Chef Anton's Gumbo Mix Chef Anton's Gumbo Mix 2
2011-10-18 12:46:15.520 2 Aniseed Syrup, Chef Anton's Cajun Seasoning, Chef Anton's Gumbo Mi Chef Anton's Gumbo Mix 3
2011-10-18 12:46:15.580 1 Changassad Changassad 1

最佳答案

这是一个有趣的问题,它也帮助我更好地理解递归 CTE。

如果您查看执行计划,您将看到使用了一个线轴,并且它设置了 WITH STACK 属性。这意味着 rows are read in a stack-like manner (Last In First Out)

所以首先 anchor 部分运行

EXEC_TIME               CategoryID  product_list  
----------------------- ----------- --------------
2011-10-18 12:46:14.930 1
2011-10-18 12:46:14.990 2
2011-10-18 12:46:15.050 4

然后 4 被处理,因为这是添加的最后一行。 JOIN 返回添加到假脱机中的 1 行,然后处理这个新添加的行。在这种情况下,Join 不会返回任何内容,因此不会向假脱机中添加任何其他内容,并且会继续处理 CategoryID = 2 行。

这将返回 3 行并添加到假脱机中

Aniseed Syrup
Chef Anton's Cajun Seasoning
Chef Anton's Gumbo Mix

然后,以类似的 LIFO 方式依次处理每一行,首先处理添加的任何子行,然后才能继续处理同级行。希望您能够了解此递归逻辑如何解释您观察到的结果,但以防万一您无法进行 C# 模拟

using System;
using System.Collections.Generic;
using System.Linq;

namespace Foo
{
internal class Bar
{
private static void Main(string[] args)
{
var spool = new Stack<Tuple<int, string, string>>();

//Add anchor elements
AddRowToSpool(spool, new Tuple<int, string, string>(1, "", ""));
AddRowToSpool(spool, new Tuple<int, string, string>(2, "", ""));
AddRowToSpool(spool, new Tuple<int, string, string>(4, "", ""));

while (spool.Count > 0)
{
Tuple<int, string, string> lastRowAdded = spool.Pop();
AddChildRows(lastRowAdded, spool);
}

Console.ReadLine();
}

private static void AddRowToSpool(Stack<Tuple<int, string, string>> spool,
Tuple<int, string, string> row)
{
Console.WriteLine("CategoryId={0}, product_list = {1}",
row.Item1,
row.Item3);
spool.Push(row);
}

private static void AddChildRows(Tuple<int, string, string> lastRowAdded,
Stack<Tuple<int, string, string>> spool)
{
int categoryId = lastRowAdded.Item1;
string productName = lastRowAdded.Item2;
string productList = lastRowAdded.Item3;

string[] products;

switch (categoryId)
{
case 1:
products = new[] {"Changassad"};
break;
case 2:
products = new[]
{
"Aniseed Syrup",
"Chef Anton's Cajun Seasoning",
"Chef Anton's Gumbo Mix "
};
break;
case 4:
products = new[] {"vcbcbvcbvc"};
break;
default:
products = new string[] {};
break;
}


foreach (string product in products.Where(
product => string.Compare(productName, product) < 0))
{
string product_list = string.Format("{0}{1}{2}",
productList,
productList == "" ? "" : ",",
product);

AddRowToSpool(spool,
new Tuple<int, string, string>
(categoryId, product, product_list));
}
}
}
}

返回

CategoryId=1, product_list =
CategoryId=2, product_list =
CategoryId=4, product_list =
CategoryId=4, product_list = vcbcbvcbvc
CategoryId=2, product_list = Aniseed Syrup
CategoryId=2, product_list = Chef Anton's Cajun Seasoning
CategoryId=2, product_list = Chef Anton's Gumbo Mix
CategoryId=2, product_list = Chef Anton's Cajun Seasoning,Chef Anton's Gumbo Mix
CategoryId=2, product_list = Aniseed Syrup,Chef Anton's Cajun Seasoning
CategoryId=2, product_list = Aniseed Syrup,Chef Anton's Gumbo Mix
CategoryId=2, product_list = Aniseed Syrup,Chef Anton's Cajun Seasoning,Chef Anton's Gumbo Mix
CategoryId=1, product_list = Changassad

关于sql-server - CTE 到底如何发挥作用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7803640/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com