我有一个复杂的子查询,它返回一个订单 ID 列表。我需要得到一份有这些订单的客户名单。问题是有两种方法可以将客户分配给订单(两个字段之一)。我可以做这样的事情:
select *
from Customers
where orderId in (select...)
or secondaryOrderId in (select ...)
Run Code Online (Sandbox Code Playgroud)
问题是子查询是巨大的,无论是执行时间还是屏幕空间。有没有办法检查其中一个字段是否包含所需的结果之一?
我遇到了这样的查询:
SELECT (SELECT COUNT(1) FROM Orders o WHERE i.ItemId = o.ItemId) [C]
FROM Items i
Run Code Online (Sandbox Code Playgroud)
我将其更改为以下
;WITH cte_count
AS
(
SELECT COUNT(1) c, OrderId FROM Orders Group By ItemId
)
SELECT a.c [Count], i.Name
FROM Items i
INNER JOIN cte_count c ON (c.ItemId = i.ItemId)
Run Code Online (Sandbox Code Playgroud)
但两者的执行计划如下所示:

同样,还有另一个查询选择TOP 1 Order By Id. 我尝试将这个移动到CROSS APPLY但是对于这个,我也得到了相同的执行计划。

当然,查询中还有其他连接和列。
我的困境是关于使用CROSS APPLYand 的实用性和优势CTE。有没有或只是异国情调?
我有一个名为的表Category,其中有一列名为CategoryID. 同一个表中有一个引用列,称为fParentCategoryID。
我需要将所有类别 ID 及其子类别 ID 以逗号分隔。例如 -如果 10 的父类别 ID 为 1,如果 20 的父类别 ID 为 10,那么当我打印类别 ID 20 时,我需要以逗号分隔值打印 1 和 10 作为其父项。
我尝试了以下查询,但我得到NULL了ParChild列。请帮忙。
;WITH
cteReports
AS
(
SELECT c.CategoryID,
c.fParentCategoryID,
[level] = 1,
ParChild=cast(CAST(c.fParentCategoryID AS VARCHAR(200)) + ',' + CAST(c.CategoryID AS VARCHAR(200)) AS VARCHAR(MAX))
FROM retail.Category c
WHERE c.fParentCategoryID is NULL
UNION ALL
SELECT c.CategoryID,
c.fParentCategoryID,
[level] + 1,
ParChild = ParChild + ',' + …Run Code Online (Sandbox Code Playgroud) 这是我在 Stack Overflow 上的问题的转贴。他们建议在这里问:
我在2005 年找到了一篇在线文章,作者声称,许多开发人员使用 GROUP BY 是错误的,您最好将其替换为子查询。
我已经在我的一个查询中对其进行了测试,我需要根据另一个表中连接条目的数量对搜索结果进行排序(更常见的条目应该首先出现)。我最初的经典方法是将两个表连接到一个公共 ID,按选择列表中的每个字段分组,并按子表的计数对结果进行排序。
现在,来自链接博客的 Jeff Smith 声称,您最好使用一个子选择,它执行所有分组,而不是加入该子选择。检查这两种方法的执行计划,SSMS 指出,大组需要 52% 的时间,子选择需要 48%,所以从技术角度来看,子选择方法实际上要快一点。但是,“改进”的 SQL 命令似乎生成了更复杂的执行计划(就节点而言)
你怎么认为?您能否详细说明在这种特定情况下如何解释执行计划,以及哪一个通常是更可取的选择?
SELECT
a.ID,
a.ID_AddressType,
a.Name1,
a.Name2,
a.Street,
a.Number,
a.ZipCode,
a.City,
a.Country
FROM dbo.[Address] a
INNER JOIN CONTAINSTABLE(
dbo.[Address],
FullAddress,
'"ZIE*"',
5
) s ON a.ID = s.[KEY]
LEFT JOIN dbo.Haul h ON h.ID_DestinationAddress = a.ID
GROUP BY
a.ID,
a.ID_AddressType,
a.Name1,
a.Name2,
a.Street,
a.Number,
a.ZipCode,
a.City,
a.Country,
s.RANK
ORDER BY s.RANK DESC, COUNT(*) DESC;
SELECT
a.ID,
a.ID_AddressType,
a.Name1, …Run Code Online (Sandbox Code Playgroud) 我(未成功)在 Invoices 表上使用相关子查询:
Invoices(InvoiceID, VendorID, InvoiceTotal, PaymentTotal, CreditTotal,.... ),
Run Code Online (Sandbox Code Playgroud)
找到所有供应商的最大未付发票的总和,其中未付条件由下式给出InvoiceTotal-PaymentTotal-CreditTotal <0:
Select Sum(LargestUnpaid) from
(Select Max(InvoiceTotal) AS LargestUnpaid from Invoices
where InvoiceTotal-(PaymentTotal+CreditTotal)<0 group by vendorID ) ;
Run Code Online (Sandbox Code Playgroud)
内部查询运行,有好有坏,因为查询应该是相关的,但查询作为一个整体没有运行,我收到错误消息:
Msg 102, Level 15, State 1, Line 4 Incorrect syntax near ')'.
Run Code Online (Sandbox Code Playgroud)
我究竟做错了什么?
假设我有两个表:
福:
id
baz
Run Code Online (Sandbox Code Playgroud)
酒吧:
id
foo_id
boom
Run Code Online (Sandbox Code Playgroud)
所以一个 Foo 有很多 Bars。我经常发现自己需要为给定的一组 Foo 计算跨条的聚合,但我也想要一些来自 Foo 的属性。这样做的两种最直接的方法是丑陋的:
方法#1:不必要的聚合函数
select
foo.id,
min(foo.baz) as baz,
min(bar.boom) as min_boom
from
foo
join
bar on foo.id = bar.foo_id
group by
foo.id;
Run Code Online (Sandbox Code Playgroud)
方法#2:不必要的按列分组
select
foo.id,
foo.baz,
min(bar.boom) as min_boom
from
foo
join
bar on foo.id = bar.foo_id
group by
foo.id,
foo.baz;
Run Code Online (Sandbox Code Playgroud)
当 Foo 除了“id”之外只有一个额外的列时,这并不是那么糟糕,但是如果需要包含许多列,那么分组的效率就会大大降低。像这样的查询解决了这两个问题,但似乎很笨拙:
select
foo.id,
foo.baz,
x.min_boom
from
foo
join
(select
foo_id,
min(boom) as min_boom
from
bar
group by
foo_id) x on x.foo_id = foo.id; …Run Code Online (Sandbox Code Playgroud) postgresql performance subquery postgresql-9.3 query-performance
SQL Server 2016,我正在尝试处理一些常规数据并返回一个 JSON 对象以供另一个系统处理。另一个系统无法识别数组包装器,因此我尝试使用 WITHOUT_ARRAY_WRAPPER 来摆脱它。在子查询中使用时会返回奇怪的结果...
SELECT @@SERVERNAME AS [Servername],
( SELECT [Name], [Recovery_Model_Desc]
FROM sys.databases
WHERE name in ('master', 'model', 'msdb')
FOR JSON PATH
) AS d
FOR JSON PATH, ROOT('ServerInformation')
Run Code Online (Sandbox Code Playgroud)
这会产生预期的数据,使用数组包装器......
{"ServerInformation":[{"Servername":"MyServer","d":[{"Name":"master","Recovery_Model_Desc":"SIMPLE"},{"Name":"model","Recovery_Model_Desc" :"FULL"},{"Name":"msdb","Recovery_Model_Desc":"SIMPLE"}]}]}
但是, WITHOUT_ARRAY_WRAPPER 产生...
SELECT @@SERVERNAME AS [Servername],
( SELECT [Name], [Recovery_Model_Desc]
FROM sys.databases
WHERE name in ('master', 'model', 'msdb')
FOR JSON PATH, WITHOUT_ARRAY_WRAPPER
) AS d
FOR JSON PATH, ROOT('ServerInformation')
Run Code Online (Sandbox Code Playgroud)
{"ServerInformation":[{"Servername":"MyServer","d":"{\"Name\":\"master\",\"Recovery_Model_Desc\":\"SIMPLE\"},{\"Name \":\"model\",\"Recovery_Model_Desc\":\"FULL\"},{\"Name\":\"msdb\",\"Recovery_Model_Desc\":\"SIMPLE\"}"}] }
而我希望它产生
{"ServerInformation":{"Servername":"MyServer","d":{"Name":"master","Recovery_Model_Desc":"SIMPLE"},{"Name":"model","Recovery_Model_Desc":" FULL"},{"Name":"msdb","Recovery_Model_Desc":"SIMPLE"}}}
错误或预期结果?
编辑:调整预期结果
在连接后跟 where 子句的情况下,使用子查询来限制结果,然后进行连接会更好吗?例子:
SELECT *
FROM Customers
NATURAL JOIN Orders
WHERE shipped=1
Run Code Online (Sandbox Code Playgroud)
在这种情况下,它接缝 DBMS 将整个客户表与整个订单表连接,然后根据 where 子句过滤结果。使用子查询的等效查询是:
SELECT *
FROM Customers
NATURAL JOIN (SELECT *
FROM Orders
WHERE shipped=1) AS O
Run Code Online (Sandbox Code Playgroud)
在这里,可能有一个较小的 Orders 表要加入。同样,如果有限制客户和订单的 where 子句:
SELECT *
FROM Customers
NATURAL JOIN Orders
WHERE country='US' AND shipped=1
(assuming country attribute belongs to Customers table)
Run Code Online (Sandbox Code Playgroud)
等效的子查询查询:
SELECT *
FROM (SELECT *
FROM Customers
WHERE country='US') AS C
NATURAL JOIN (SELECT *
FROM Orders
WHERE shipped=1) AS O
Run Code Online (Sandbox Code Playgroud) 在下面的示例中,我有一个表foo,我想从中随机选择每组的一行。
CREATE TABLE foo (
line INT
);
INSERT INTO foo (line)
SELECT generate_series(0, 999, 1);
Run Code Online (Sandbox Code Playgroud)
假设我想按 分组line % 10。我可以这样做:
SELECT DISTINCT ON (bin) bin, line
FROM (
SELECT line, line % 10 AS bin, random() x
FROM foo
ORDER BY x
) X
Run Code Online (Sandbox Code Playgroud)
我想做的是多次从每个垃圾箱中随机选择。我原以为我能和做到这一点generate_series(),并LATERAL
SELECT i, line, bin
FROM
(
SELECT generate_series(1,3) i
) m,
LATERAL
(SELECT DISTINCT ON (bin) bin, line
FROM (
SELECT line, line % 10 bin, random() x …Run Code Online (Sandbox Code Playgroud) 我在 MySQL 数据库中有两个表 -t1一个列c1,t2一个列c2。
我运行这个查询:
select * from t1 where c1 in (select c1 from t2);
Run Code Online (Sandbox Code Playgroud)
上面的查询应该给出一个错误,因为c1t2 中不存在。相反,它返回t1. 上述查询的另一个版本delete可能会造成更大的灾难:
delete from t1 where c1 in (select c1 from t2);
Run Code Online (Sandbox Code Playgroud)
当上面的查询只是应该给出错误时,它会删除 t1 中的所有行。
我注意到只有当子查询中的列与外部列具有相同的名称时才会发生这种行为。意义,
select * from t1 where c1 in (select c3 from t2);
Run Code Online (Sandbox Code Playgroud)
将按预期抛出错误:
ERROR 1054 (42S22): Unknown column 'c3' in 'field list'
Run Code Online (Sandbox Code Playgroud)
顺便说一句,我已经在 PostgreSQL 9.6.3 上检查过同样的问题,行为完全相同。对这种奇怪的行为有什么解释吗?
subquery ×10
sql-server ×4
cte ×3
performance ×2
postgresql ×2
t-sql ×2
cross-apply ×1
join ×1
json ×1
optimization ×1
random ×1