sql cross join - 有人发现它有啥用处? [关闭]
Posted
技术标签:
【中文标题】sql cross join - 有人发现它有啥用处? [关闭]【英文标题】:sql cross join - what use has anyone found for it? [closed]sql cross join - 有人发现它有什么用处? [关闭] 【发布时间】:2010-10-06 02:29:32 【问题描述】:今天,在使用 sql server 开发 10 年来,我第一次在生产查询中使用了交叉联接。我需要将结果集填充到报告中,并发现使用创造性 where 子句在两个表之间进行交叉连接是一个很好的解决方案。我想知道有人在交叉连接的生产代码中发现了什么用途?
更新:Tony Andrews 发布的代码与我使用交叉连接的代码非常接近。相信我,我理解使用交叉连接的含义并且不会轻易这样做。我很高兴终于使用了它(我真是个书呆子)——有点像我第一次使用完全外连接的时候。
感谢大家的回答!以下是我使用交叉连接的方式:
SELECT CLASS, [Trans-Date] as Trans_Date,
SUM(CASE TRANS
WHEN 'SCR' THEN [Std-Labor-Value]
WHEN 'S+' THEN [Std-Labor-Value]
WHEN 'S-' THEN [Std-Labor-Value]
WHEN 'SAL' THEN [Std-Labor-Value]
WHEN 'OUT' THEN [Std-Labor-Value]
ELSE 0
END) AS [LABOR SCRAP],
SUM(CASE TRANS
WHEN 'SCR' THEN [Std-Material-Value]
WHEN 'S+' THEN [Std-Material-Value]
WHEN 'S-' THEN [Std-Material-Value]
WHEN 'SAL' THEN [Std-Material-Value]
ELSE 0
END) AS [MATERIAL SCRAP],
SUM(CASE TRANS WHEN 'RWK' THEN [Act-Labor-Value] ELSE 0 END) AS [LABOR REWORK],
SUM(CASE TRANS
WHEN 'PRD' THEN [Act-Labor-Value]
WHEN 'TRN' THEN [Act-Labor-Value]
WHEN 'RWK' THEN [Act-Labor-Value]
ELSE 0
END) AS [ACTUAL LABOR],
SUM(CASE TRANS
WHEN 'PRD' THEN [Std-Labor-Value]
WHEN 'TRN' THEN [Std-Labor-Value]
ELSE 0
END) AS [STANDARD LABOR],
SUM(CASE TRANS
WHEN 'PRD' THEN [Act-Labor-Value] - [Std-Labor-Value]
WHEN 'TRN' THEN [Act-Labor-Value] - [Std-Labor-Value]
--WHEN 'RWK' THEN [Act-Labor-Value]
ELSE 0 END) -- - SUM([Std-Labor-Value]) -- - SUM(CASE TRANS WHEN 'RWK' THEN [Act-Labor-Value] ELSE 0 END)
AS [LABOR VARIANCE]
FROM v_Labor_Dist_Detail
where [Trans-Date] between @startdate and @enddate
--and CLASS = (CASE @class WHEN '~ALL' THEN CLASS ELSE @class END)
GROUP BY [Trans-Date], CLASS
UNION --REL 2/6/09 Pad result set with any missing dates for each class.
select distinct [Description] as class, cast([Date] as datetime) as [Trans-Date], 0,0,0,0,0,0
FROM Calendar_To_Fiscal cross join PRMS.Product_Class
where cast([Date] as datetime) between @startdate and @enddate and
not exists (select class FROM v_Labor_Dist_Detail vl where [Trans-Date] between @startdate and @enddate
and vl.[Trans-Date] = cast(Calendar_To_Fiscal.[Date] as datetime)
and vl.class= PRMS.Product_Class.[Description]
GROUP BY [Trans-Date], CLASS)
order by [Trans-Date], CLASS
【问题讨论】:
【参考方案1】:交叉连接的典型合法用途是显示例如按产品和地区划分的总销售额。如果区域 R 中的产品 P 没有销售,那么我们希望看到一行为零,而不是不显示一行。
select r.region_name, p.product_name, sum(s.sales_amount)
from regions r
cross join products p
left outer join sales s on s.region_id = r.region_id
and s.product_id = p.product_id
group by r.region_name, p.product_name
order by r.region_name, p.product_name;
【讨论】:
数据或结果的一些视觉效果在这里会很有帮助。【参考方案2】:我经常遇到的一种用途是将记录拆分为几条记录,主要用于报告目的。
想象一个字符串,其中每个字符代表相应小时内的某个事件。
ID | Hourly Event Data
1 | -----X-------X-------X--
2 | ---X-----X------X-------
3 | -----X---X--X-----------
4 | ----------------X--X-X--
5 | ---X--------X-------X---
6 | -------X-------X-----X--
现在您需要一份报告,显示在哪一天发生了多少事件。将表与 ID 为 1 到 24 的表交叉连接,然后施展你的魔法......
SELECT
[hour].id,
SUM(CASE WHEN SUBSTRING([data].string, [hour].id, 1) = 'X' THEN 1 ELSE 0 END)
FROM
[data]
CROSS JOIN
[hours]
GROUP BY
[hours].id
=>
1, 0
2, 0
3, 0
4, 2
5, 0
6, 2
7, 0
8, 1
9, 0
10, 2
11, 0
12, 0
13, 2
14, 1
15, 0
16, 1
17, 2
18, 0
19, 0
20, 1
21, 1
22, 3
23, 0
24, 0
【讨论】:
在这种情况下,您的数据甚至不是第一范式吗?一天中的所有 24 小时都存储在一个字段中。这不是真正的问题吗? @kralco626 - 仅仅因为规范化有利于关系数据库,这并不意味着您的源数据就是以这种方式构建的。例如,SAS 通常会产生保证以这种方式进行旋转的数据集,或者提供状态跟踪字符串的微控制器等。因此,这可以构成 ETL 的一部分。【参考方案3】:我有不同的报告对记录集进行预过滤(按公司内的各种业务线),但有些计算需要公司范围内的收入百分比。记录源必须包含公司总数,而不是依赖于计算报告本身中的总和。
示例:记录集包含每个客户的余额以及客户收入来源的业务线。该报告可能只显示“零售”客户。无法获得整个公司的余额总和,但报告显示了公司收入的百分比。
由于有不同的余额字段,我觉得完全联接具有多个余额的视图(我也可以重用该公司总计视图)而不是多个字段组成子查询的复杂性更小。
另一种是更新语句,需要创建多条记录(预设工作流程中的每个步骤都有一条记录)。
【讨论】:
【参考方案4】:这是一个,CROSS JOIN 代替了 INNER JOIN。当要连接的两个表之间没有相同的值时,这是有用且合法的。例如,假设您有一个表,其中包含某个语句或公司文档的版本 1、版本 2 和版本 3,所有这些都保存在 SQL Server 表中,以便您可以即时重新创建与订单关联的文档,在订单很久之后,并且在您的文档被重写为新版本之后很久。但是您需要连接的两个表(Documents 表)中只有一个具有 VersionID 列。这是一种方法:
SELECT DocumentText, VersionID =
(
SELECT d.VersionID
FROM Documents d
CROSS JOIN Orders o
WHERE o.DateOrdered BETWEEN d.EffectiveStart AND d.EffectiveEnd
)
FROM Documents
【讨论】:
【参考方案5】:我最近在我们用于销售预测的报告中使用了 CROSS JOIN,该报告需要细分销售人员在每个总帐帐户中完成的销售额。
所以在报告中我为此做了一些事情:
SELECT gla.AccountN, s.SalespersonN
FROM
GLAccounts gla
CROSS JOIN Salesperson s
WHERE (gla.SalesAnalysis = 1 OR gla.AccountN = 47500)
这为我提供了每个销售人员的每个 GL 帐户,例如:
销售Psn AccountN 1000 40100 1000 40200 1000 40300 1000 48150 1000 49980 1000 49990 1005 40100 1005 40200 1005 40300 1054 48150 1054 49980 1054 49990 1078 40100 1078 40200 1078 40300 1078 48150 1078 49980 1078 49990 1081 40100 1081 40200 1081 40300 1081 48150 1081 49980 1081 49990 1188 40100 1188 40200 1188 40300 1188 48150 1188 49980 1188 49990【讨论】:
很难从您的示例中看出,但看起来您可以使用普通的 JOIN 并获得相同的结果。 带有“where”子句的交叉连接与使用内部连接相同(参见此处 - msdn.microsoft.com/en-us/library/ms190690.aspx)【参考方案6】:用于图表(报告),其中每个分组都必须有记录,即使它为零。 (例如 RadCharts)
【讨论】:
【参考方案7】:我的源数据中有 am insolvency 字段的组合。 有 5 种不同的类型,但数据包含其中 2 种的组合。所以我创建了 5 个不同值的查找表,然后使用交叉连接插入语句来填写其余部分。像这样
insert into LK_Insolvency (code,value)
select a.code+b.code, a.value+' '+b.value
from LK_Insolvency a
cross join LK_Insolvency b
where a.code <> b.code <--this makes sure the x product of the value with itself is not used as this does not appear in the source data.
【讨论】:
【参考方案8】:我个人尽量避免在我的查询中使用笛卡尔积。我想你的每个连接组合都有一个结果集可能很有用,但通常如果我最终得到一个,我知道我有问题。
【讨论】:
不确定这个答案是否相关:大概你只在不合适时避免交叉连接,而不是在合适时避免? @Tony:是的——当交叉连接不合适时,你会避免交叉连接,而且它们不合适的频率远比合适的多。但是,当它们适当时,它们是处理某些问题的最佳方法。答案与不相关。 +0 我也是,这就是我问这个问题的原因... ;-)以上是关于sql cross join - 有人发现它有啥用处? [关闭]的主要内容,如果未能解决你的问题,请参考以下文章
ActivityManager 中的奇怪函数:isUserAMonkey。这是啥意思,它有啥用?