4

私のデータは次のようになります。

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

最初のケースでは、猫とサブ猫で合計する必要があります。簡単:

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...しかし、ゼロとして表示する2番目の要件に失敗します。

出来ますか?

私はSybaseIQ12.5を使用しています(つまり、古いT-SQLですが、case有用であると思われるステートメントがあります)

4

6 に答える 6

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

ユニオン付きの派生テーブルを使用し、実際のデータセットが質問で指定したものよりもはるかに大きいことを考えると、SELECT ... INTO実際には更新が続く方がパフォーマンスの高いアプローチであると思います!

于 2011-12-06T03:26:27.887 に答える
1

B2 を B1 に変換するには結合が必要です。Data -> Config -> Data次に 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で実際の例を見ることができます。

複数のロールアップされた SubCat がある場所をテストするために、3 番目の「B」値を追加したことに注意してください。

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

このdata.seクエリで表示できるもの

于 2011-12-06T03:46:09.677 に答える
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)
于 2011-12-06T05:10:08.197 に答える
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% です。その方が効率がいいということですか?または、それは単に依存します:)

于 2011-12-06T03:26:19.010 に答える
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

ここの例 - https://data.stackexchange.com/stackoverflow/q/120507/

それがあなたの意図したものではない場合はお知らせください。

于 2011-12-06T02:24:24.507 に答える
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
于 2011-12-06T09:46:15.737 に答える