我的数据如下:
|cat |subcat |amount|
---------------------
|A |1 |123 |
|A |2 |456 |
|B |1 |222 |
|B |2 |333 |
在第一种情况下,我需要用cat和subcat求和。易:
SELECT cat, subcat, sum(amount) FROM data GROUP BY cat, subcat
接下来,我有一个更复杂的要求,对于某些猫,应该将数量“推”到给定的子猫中。这可以存储在另一个config
表中:
|cat |subcat|
-------------
|B |1 |
这告诉我,对于所有cat='B'
行,金额应被视为subcat=1
。此外,cat='B' AND subcat <> 1
的数量应报告为零。换句话说,我需要的结果是:
|cat |subcat|amount|
|A |1 |123 |
|A |2 |456 |
|B |1 |555 |
|B |2 |0 |
我无法更新数据表。当然我可以在proc中SELECT ... INTO
并在那里修复数据,但我想知道它是否可以在一次点击中完成。
我可以非常接近:
SELECT data.cat,
ISNULL(config.subcat, data.subcat),
SUM(amount)
FROM data
LEFT OUTER JOIN config ON (data.cat = config.cat)
GROUP BY data.cat, ISNULL(config.subcat, data.subcat)
...但是我的第二个要求是将cat:B, subcat:2
显示为零。
有可能吗?
我正在使用Sybase IQ 12.5(即旧的T-SQL,但是有case
语句,我怀疑它可能有用)
答案 0 :(得分:1)
这就是我想出的。
SELECT cat, subcat, sum(amount)
FROM
(
SELECT d.cat,
d.subcat,
CASE WHEN c.subcat <> d.subcat THEN 0 ELSE amount END amount
FROM data d
LEFT OUTER JOIN config c ON (d.cat = c.cat)
UNION
SELECT d.cat,
ISNULL(c.subcat, d.subcat),
amount
FROM data d
LEFT OUTER JOIN config c ON (d.cat = c.cat)
WHERE c.subcat <> d.subcat
) AS data2
GROUP BY cat, subcat
鉴于它使用带有union的派生表,并且我的实际数据集比我在问题中提供的数据集大得多,我认为SELECT ... INTO
后跟更新可能实际上更高效接近!
答案 1 :(得分:1)
您需要使用连接Data -> Config -> Data
将B2转换为B1,然后将UNION转换为带有Case语句的SELECT,然后将SUM和GROUP BY转换为
SELECT
t.CAT,
t.SUBCAT,
SUM(t.AMOUNT) AMOUNT
FROM
(
SELECT d.cat,
d.subcat,
CASE
WHEN c.subcat IS NULL
OR c.subcat = d.subcat THEN d.amount
ELSE 0
END AS amount
FROM data d
LEFT JOIN config c
ON d.cat = c.cat
UNION ALL
SELECT d.cat,
d.subcat,
d2.amount
FROM data d
INNER JOIN config c
ON ( d.cat = c.cat )
INNER JOIN data d2
ON c.cat = d2.cat
AND c.subcat <> d2.subcat
AND c.subcat = d.subcat
) t
GROUP BY
cat,
subcat
ORDER BY
cat,
subcat
您可以在此data.se query看到一个有效的例子。
注意我添加了第三个“B”值来测试多个卷起SubCat的位置
另一种使用WITH和ROLLUP子句的方法(Sybase的某些版本支持哪些我不知道哪个)
with g as (
SELECT
d.cat,
d.subcat,
c.subcat config_subcat,
sum(amount) amount,
GROUPING(c.subcat) subcatgroup
FROM data d
LEFT JOIN config c
ON d.cat = c.cat
GROUP BY
d.cat,
d.subcat,
c.subcat with rollup
)
SELECT
g.cat,
g.subcat,
case when g.config_subcat is null then g.amount
WHEN g.subcat = g.config_subcat THEN g2.amount
ELSE 0 end amount
FROM g
LEFT JOIN g g2
ON g.cat = g2.cat and g2.subcatgroup= 1
and g.subcat is not null and g2.subcat is null
WHERE g.subcatgroup= 0
查看
答案 2 :(得分:0)
我对这些要求感到有点困惑,但我认为这就是你想要的。
SELECT d.cat,
d.subcat,
SUM(CASE
WHEN c.subcat IS NULL OR c.subcat = d.subcat
THEN d.amount
ELSE 0
END) as Amount
FROM @Data d
LEFT OUTER JOIN @Config c ON (d.cat = c.cat)
GROUP BY d.cat, d.subcat
ORDER BY d.cat
此处示例 - http://data.stackexchange.com/stackoverflow/q/120507/
请告诉我这是不是你想要的。
答案 3 :(得分:0)
我正在使用tsql,这是我的代码。这很丑,但有效。实际上,我喜欢你非常接近的方法(如果你不坚持显示B2 = 0)。
SELECT A.cat,
A.subcat,
CASE WHEN B.IsConfig = 0 THEN A.amount
WHEN B.IsConfig = 1 AND C.cat IS NULL THEN 0
ELSE B.amount
END AS amount
FROM data A
INNER JOIN
(
SELECT B1.cat, B1.amount, CASE WHEN C1.cat IS NULL THEN 0 ELSE 1 END AS IsConfig
FROM
(
SELECT cat, SUM(amount) amount
FROM data
GROUP BY cat
) B1 LEFT OUTER JOIN config C1 ON B1.cat = C1.cat
) B ON A.cat = B.cat
LEFT OUTER JOIN config C ON A.cat = C.cat AND A.subcat = C.subcat
---我不能评论别人,所以我在这里添加我的问题---
使用执行计划将我的代码与其他代码进行比较,我的查询成本为46%。这是否意味着它更有效率?或者它只取决于:)
答案 4 :(得分:0)
为派生表中“config”中引用的所有“cat”计算SUM(amount)
,然后根据需要将其与“data”表条目匹配:
SELECT data.cat,
data.subcat,
CASE
WHEN dt.subcat IS NULL -- no "config" entry for cat
THEN data.amount
WHEN dt.subcat = data.subcat -- "config" for cat and subcat
THEN dt.total
ELSE 0 -- "config" for cat not subcat
END AS amount
FROM data
LEFT JOIN ( SELECT config.cat,
config.subcat,
SUM(data.amount) AS total
FROM config
JOIN data USING (cat)
GROUP BY 1, 2 ) dt
USING (cat);
+-----+--------+--------+
| cat | subcat | amount |
+-----+--------+--------+
| A | 1 | 123 |
| A | 2 | 456 |
| B | 1 | 555 |
| B | 2 | 0 |
+-----+--------+--------+
4 rows in set (0.00 sec)
答案 5 :(得分:0)
这与您的解决方案有点类似,但UNION
仅用于构建类别和子类别列表。然后该列表与另一个派生表连接,该表与UNION的右侧部分基本相同。这是:
SELECT s.cat, s.subcat, ISNULL(SUM(d.amount), 0)
FROM (
SELECT cat, subcat FROM data
UNION
SELECT cat, subcat FROM config
) s
LEFT JOIN (
SELECT
d.cat,
subcat = ISNULL(c.subcat, d.subcat),
d.amount
FROM data d
LEFT JOIN config c ON d.cat = c.cat
) d ON s.cat = d.cat AND s.subcat = d.subcat
GROUP BY s.cat, s.subcat