2011-12-06 13 views
4

私のデータを合計するには次のようになります。最初のケースでSQL条件付きのグループ化と

|cat |subcat |amount| 
--------------------- 
|A |1  |123 | 
|A |2  |456 | 
|B |1  |222 | 
|B |2  |333 | 

、私は猫と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  | 

データテーブルを更新できません。もちろん、私はSELECT ... INTOのprocでデータを修正することができますが、1ヒットで実行できるかどうかは疑問です。

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文を、持っていているに)

+1

私はかなりこの部分に従っていません:「これは、すべての猫= 『B』の行について、量は= 1 SUBCATとして扱われるべきであることを私に告げるさらに、どこの猫= 'B。 'AND subcat <> 1量はゼロとして報告されるべきです。最初の文から、[B、2]は333ではなく222の量として扱われなければならないが、2番目の文[B、2]は333ではなく0として扱われるべきである。ルールが適用されたときに処理する必要がありますか? – Glenn

答えて

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/

それはあなたがのために行っていたものではないのですなら、私に教えてください。

+0

'B | 1 | 222'の行は' B | 2 | 0'(良い)ですが、 'B | 1 | 555'が – Rob

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%です。それがより効率的であることを意味しますか?またはそれはちょうど依存しています:

1

私は思いつきました。それは組合と派生テーブルを使用し、私の実際のデータセットは、私が質問に与えたものよりはるかに大きいことを、私は更新が続くSELECT ... INTOが実際よりパフォーマンスかもしれないと思うことを考えると

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 

アプローチ!

1

あなたは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 
​ 

簡単であることをあなたが作業例を見ることができ、次にUNIONをB1にB2を変換するために参加Data -> Config -> Dataする必要がありますこのdata.se queryで。そこに2つ以上が

わからないのSybaseの一部のバージョンでサポートされているWITHとROLLUP句を(使用する別のアプローチSUBCAT

を巻き上げ場合

注私はテストするために第三の「B」の値を追加しましたこれ)で見ることができ

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​​ 

このdata.se query

+0

の場合は' config'に含まれていないサブカテゴリ特定のカテゴリの 'data'ですか?あなたのソリューションはそれを説明していないようです。 –

+0

それは要件ではありませんか?私はそれが完全な外部結合といくつかの石炭で固定することができると思います。 –

+0

いいえ、OPはそれについて何も言わないので、もちろん、状況が不可能であるか、他の場所で説明されていると仮定するのは大丈夫です。それ以外のソリューションは正しく動作します。 –

0

派生表の「設定」で参照されるすべての「猫」のための計算SUM(amount)、その後、必要に応じて、あなたの「データ」テーブルエントリを持つものと一致:

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) 
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