我有两个问题,如下所示。查询选择相同的表,但具有不同的条件和列数。我无法解决如何将这些结合起来;有什么办法吗?
第一个查询是:
SELECT b.centerBranchNumber,
b.countryCode,
a.type,
SUM(DECODE(a.status, 1, 1, 0)) filled
FROM tableA a,
tableB b
WHERE a.branchCode = b.branchCode
AND a.registerNumber IN (SELECT c.registerNumber
FROM tableC c
WHERE c.registerDate <= '01.02.2013'
AND c.state = 'A'
AND c.contractState != 2)
GROUP BY b.centerBranchNumber,
b.countryCode,
a.type;
结果如下:
BranchNumber CountryCode Type Filled
1452 USA 0 5
1452 USA 2 8
1452 USA 1 16
7854 GER 0 10
7854 GER 1 3
第二个查询是:
SELECT b.centerBranchNumber,
b.countryCode,
a.type,
SUM(DECODE(a.status, 0, 1, 0)) free,
SUM(DECODE(a.status, 2, 1, 0)) damaged
FROM tableA a,
tableB b
WHERE a.kks_kayitdrm = 'A'
AND a.branchCode = b.branchCode
AND a.recordDate <= '01.02.2013'
GROUP BY b.centerBranchNumber,
a.type,
b.countryCode;
结果是:
BranchNumber CountryCode Type Free Damage
1452 USA 0 5 2
1452 USA 2 8 1
1452 USA 1 16 5
7854 GER 0 10 9
7854 GER 1 3 16
如果我合并,我希望结果如下:
BranchNumber CountryCode Type Filled Free Damage
1452 USA 0 1 5 2
1452 USA 2 2 8 1
1452 USA 1 65 16 5
7854 GER 0 7 10 9
7854 GER 1 45 3 16
答案 0 :(得分:1)
您的第一个查询可以重写如下:
SELECT b.centerBranchNumber,
b.countryCode,
a.type,
SUM(DECODE(a.status, 1, 1, 0)) filled
FROM tableA a
JOIN tableB b
ON a.branchCode = b.branchCode
JOIN tableC
ON a.registerNumber = c.registerNumber
WHERE c.registerDate <= '01.02.2013'
AND c.state = 'A'
AND c.contractState != 2
GROUP BY b.centerBranchNumber,
b.countryCode,
a.type
将您的第二个转换为ANSI语法(它会帮助处理更复杂的查询,因为当您做错了事情时它非常明显)它会变成这样:
SELECT b.centerBranchNumber,
b.countryCode,
a.type,
SUM(DECODE(a.status, 0, 1, 0)) free,
SUM(DECODE(a.status, 2, 1, 0)) damaged
FROM tableA a
JOIN tableB b
ON a.branchCode = b.branchCode
WHERE a.kks_kayitdrm = 'A'
AND a.recordDate <= '01.02.2013'
GROUP BY b.centerBranchNumber,
a.type,
b.countryCode
正如您所看到的,两个查询之间存在大量相似性。为了获得您想要的结果集,有两种方法可以实现。将不相似的条件移动到SUM中的CASE语句中。或者,您可以将两个查询联合起来并再次求和。我宁愿使用CASE声明,因为你减少了你必须做的工作量;缺点是查询变得不那么容易阅读。
您的查询的常见部分是:
SELECT b.centerBranchNumber,
b.countryCode,
a.type
FROM tableA a
JOIN tableB b
ON a.branchCode = b.branchCode
GROUP BY b.centerBranchNumber,
a.type,
b.countryCode
以此为基础,您可以慢慢添加它,直到获得相同的结果。您必须记住将相同的条件添加到WHERE / JOINS以确保获得相同的结果。
如果我们先添加所有条件;你必须在第一个查询中将tableC上的JOIN更改为LEFT OUTER JOIN。这与WHERE子句将限制结果集完全相同,就好像它是一个INNER JOIN。
SELECT b.centerBranchNumber,
b.countryCode,
a.type
FROM tableA a
JOIN tableB b
ON a.branchCode = b.branchCode
LEFT OUTER JOIN tableC
ON a.registerNumber = c.registerNumber
WHERE c.registerDate <= '01.02.2013'
AND c.state = 'A'
AND c.contractState != 2
GROUP BY b.centerBranchNumber,
b.countryCode,
a.type
在第二个查询中添加条件,您现在需要在WHERE子句中使用OR:
SELECT b.centerBranchNumber,
b.countryCode,
a.type
FROM tableA a
JOIN tableB b
ON a.branchCode = b.branchCode
LEFT OUTER JOIN tableC
ON a.registerNumber = c.registerNumber
WHERE ( c.registerDate <= '01.02.2013'
AND c.state = 'A'
AND c.contractState != 2
)
OR ( a.kks_kayitdrm = 'A'
AND a.recordDate <= '01.02.2013'
)
GROUP BY b.centerBranchNumber,
b.countryCode,
a.type
接下来,你的日期似乎有点奇怪。您似乎没有将字符串文字'01.02.2013'
转换为日期,因为它不是YYYYMMDD形式,您的比较将无法正常工作。您依赖于DD.MM.YYYY
格式为WHERE ( c.registerDate <= to_date('01.02.2013', 'dd.mm.yyyy')
的{{1}},您无法保证每次会话。要比较日期,您应该使用内置的NLS_DATE_FORMAT函数以及相应的TO_DATE()
或ANSI format model进行显式转换,因为我在datetime literal中进行了更全面的解释
我只想说Oracle this answer因为:
使用显式数据类型转换函数时,SQL语句更容易理解。
隐式数据类型转换可能会对性能产生负面影响,尤其是当列值的数据类型转换为常量的数据类型而不是相反时。
隐式转换取决于它发生的上下文,并且在每种情况下可能无法以相同的方式工作。例如,从datetime值到VARCHAR2值的隐式转换可能会返回意外的年份,具体取决于NLS_DATE_FORMAT的值 参数。
隐式转换的算法可能会在软件版本和Oracle产品之间发生变化。显式转换的行为更具可预测性。
为了比较您的日期,我建议您使用TO_DATE(),例如:
registerNumber
最后我们可以添加SUMs;这意味着重复您之前的条件。您可以为第一个查询简化此操作,因为某些内容是否已“填充”仅取决于LEFT OUTER JOIN,这意味着如果该表中的SELECT b.centerBranchNumber
, b.countryCode
, a.type
, sum(case when a.status = 1 and c.registernumber is not null then 1
else 0
end) as filled
, sum(case when a.status = 0
and a.kks_kayitdrm = 'A'
and a.recordDate <= to_date('01.02.2013', 'dd.mm.yyyy')
then 1
else 0
end) as free
, sum(case when a.status = 2
and a.kks_kayitdrm = 'A'
and a.recordDate <= to_date('01.02.2013', 'dd.mm.yyyy')
then 1
else 0
end) as damaged
FROM tableA a
JOIN tableB b
ON a.branchCode = b.branchCode
LEFT OUTER JOIN tableC
ON a.registerNumber = c.registerNumber
WHERE ( c.registerDate <= to_date('01.02.2013', 'dd.mm.yyyy')
AND c.state = 'A'
AND c.contractState != 2
)
OR ( a.kks_kayitdrm = 'A'
AND a.recordDate <= to_date('01.02.2013', 'dd.mm.yyyy')
)
GROUP BY b.centerBranchNumber
, b.countryCode
, a.type
在JOIN中不为null,则条件为true
在这两种情况下,我使用CASE语句而不是DECODE;这是因为CASE功能更强大,并强制执行正确的数据类型explicitly recommends against using implicit conversion。
将所有这些放在一起成为您的最终查询:
{{1}}
您可以更通用地使用此方法在适当的位置组合查询。