sql cross join - 有人找到了什么用途?

时间:2009-02-07 03:50:39

标签: sql-server database tsql cross-join

今天,在使用sql server进行10年开发的第一次中,我在生产查询中使用了交叉连接。我需要将结果集填充到报表中,并发现具有creative 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

8 个答案:

答案 0 :(得分:36)

交叉联接的典型合法用途是显示例如交叉联接的报告。按产品和地区划分的总销售额如果没有在区域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;

答案 1 :(得分:11)

我经常遇到的一个用途是将记录分成几个记录,主要用于报告目的。

想象一个字符串,其中每个字符代表相应小时内的某个事件。

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

答案 2 :(得分:2)

我有不同的报告预先过滤记录集(通过公司内部的各种业务线),但有计算需要公司范围内的收入百分比。记录源必须包含公司总数,而不是依赖于计算报告本身的总和。

示例:记录集包含每个客户的余额以及客户收入来自的业务线。该报告可能只显示“零售”客户。无法获得整个公司的余额总和,但报告显示了公司收入的百分比。

由于存在不同的余额字段,我觉得完全加入具有多个余额的视图(我也可以重复使用此公司总计视图)而不是多个字段组成子查询的情况并不复杂。

另一个是更新语句,其中需要创建多个记录(预设工作流程中每个步骤的一个记录)。

答案 3 :(得分:1)

这是一个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 

答案 4 :(得分:0)

我最近在用于销售预测的报告中使用了CROSS JOIN,报告需要打破销售人员在每个总帐帐户中所做的销售额。

所以在报告中我做了一些事情:

SELECT gla.AccountN, s.SalespersonN
FROM
    GLAccounts gla
    CROSS JOIN Salesperson s
WHERE (gla.SalesAnalysis = 1 OR gla.AccountN = 47500)

这为每个销售人员提供了每个GL帐户:

SalesPsn    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

答案 5 :(得分:0)

对于图表(报告),每个分组必须有一个记录,即使它是零。 (例如RadCharts)

答案 6 :(得分:0)

我从源数据中得到了破产现场的组合。 有5种不同的类型,但数据具有其中2种的组合。所以我创建了5个不同值的查找表,然后使用交叉连接为insert语句填写其余值。像这样

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.

答案 7 :(得分:-3)

我个人试图在我的查询中避免使用笛卡尔积。我想有一个结果集,你的联接的每个组合都可能有用,但通常如果我最终得到一个,我知道我有什么不对。