7

SQLの課題があり、少し助けが必要です。

以下は単純化された例です。私の実際のケースでは、低速のVIEWに約500k行あります。ですから、もしあなたが同様に効果的な解決策を持っているなら、私はそれをいただければ幸いです。何らかの方法でGROUPBYを使用する必要があると思いますが、よくわかりません。

このようなテーブルがあるとしましょう

╔═════════╦══════════╦══════════╦═══════╗
║ ORDERID ║   NAME   ║   TYPE   ║ PRICE ║
╠═════════╬══════════╬══════════╬═══════╣
║       1 ║ Broccoli ║ Food     ║ 1     ║
║       1 ║ Beer     ║ Beverage ║ 5     ║
║       1 ║ Coke     ║ Beverage ║ 2     ║
║       2 ║ Beef     ║ Food     ║ 2.5   ║
║       2 ║ Juice    ║ Beverage ║ 1.5   ║
║       3 ║ Beer     ║ Beverage ║ 5     ║
║       4 ║ Tomato   ║ Food     ║ 1     ║
║       4 ║ Apple    ║ Food     ║ 1     ║
║       4 ║ Broccoli ║ Food     ║ 1     ║
╚═════════╩══════════╩══════════╩═══════╝

だから私がしたいのは:

食べ物と飲み物の両方の注文ラインがある各注文で、最高の飲み物の価格が欲しい

したがって、この例では、次の結果セットが必要です。

╔═════════╦═══════╦═══════╗
║ ORDERID ║ NAME  ║ PRICE ║
╠═════════╬═══════╬═══════╣
║       1 ║ Beer  ║ 5     ║
║       2 ║ Juice ║ 1.5   ║
╚═════════╩═══════╩═══════╝

どうすればこれを効果的に達成できますか?

4

4 に答える 4

3

max(price)食べ物と飲み物の両方で注文ごとにを取得するサブクエリを使用し、それをテーブルに結合して結果を取得できます。

select t1.orderid,
  t1.name,
  t1.price
from yourtable t1
inner join
(
  select max(price) MaxPrice, orderid
  from yourtable t
  where type = 'Beverage'
    and exists (select orderid
                from yourtable o
                where type in ('Food', 'Beverage')
                  and t.orderid = o.orderid
                group by orderid
                having count(distinct type) = 2)
  group by orderid
) t2
  on t1.orderid = t2.orderid
  and t1.price = t2.MaxPrice

SQL FiddlewithDemoを参照してください

結果は次のとおりです。

| ORDERID |  NAME | PRICE |
---------------------------
|       1 |  Beer |     5 |
|       2 | Juice |   1.5 |
于 2013-01-18T11:34:07.843 に答える
2

これは関係除算です:リンク1リンク2

除数テーブル(食品飲料のみ)が静的である場合は、次のいずれかのソリューションを使用できます。

DECLARE @OrderDetail TABLE 
    ([OrderID] int, [Name] varchar(8), [Type] varchar(8), [Price] decimal(10,2))
;

INSERT INTO @OrderDetail
    ([OrderID], [Name], [Type], [Price])
SELECT 1, 'Broccoli', 'Food', 1.0
UNION ALL SELECT 1, 'Beer', 'Beverage', 5.0
UNION ALL SELECT 1, 'Coke', 'Beverage', 2.0
UNION ALL SELECT 2, 'Beef', 'Food', 2.5
UNION ALL SELECT 2, 'Juice', 'Beverage', 1.5
UNION ALL SELECT 3, 'Beer', 'Beverage', 5.0
UNION ALL SELECT 4, 'Tomato', 'Food', 1.0
UNION ALL SELECT 4, 'Apple', 'Food', 1.0
UNION ALL SELECT 4, 'Broccoli', 'Food', 1.0

-- Solution 1
SELECT  od.OrderID, 
        COUNT(DISTINCT od.Type) AS DistinctTypeCount, 
        MAX(CASE WHEN od.Type='beverage' THEn od.Price END) AS MaxBeveragePrice
FROM    @OrderDetail od
WHERE   od.Type IN ('food', 'beverage')
GROUP BY od.OrderID
HAVING  COUNT(DISTINCT od.Type) = 2 -- 'food' & 'beverage'

-- Solution 2: better performance
SELECT  pvt.OrderID,
        pvt.food AS MaxFoodPrice,
        pvt.beverage AS MaxBeveragePrice
FROM (
    SELECT  od.OrderID, od.Type, od.Price
    FROM    @OrderDetail od
    WHERE   od.Type IN ('food', 'beverage')
) src
PIVOT ( MAX(src.Price) FOR src.Type IN ([food], [beverage]) ) pvt
WHERE   pvt.food IS NOT NULL
AND     pvt.beverage IS NOT NULL

結果(ソリューション1および2の場合):

OrderID     DistinctTypeCount MaxBeveragePrice
----------- ----------------- ---------------------------------------
1           2                 5.00
2           2                 1.50

Table 'Worktable'. Scan count 2, logical reads 23, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table '#09DE7BCC'. Scan count 1, logical reads 1, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

OrderID     MaxFoodPrice                            MaxBeveragePrice
----------- --------------------------------------- ---------------------------------------
1           1.00                                    5.00
2           2.50                                    1.50

Table '#09DE7BCC'. Scan count 1, logical reads 1, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
于 2013-01-18T12:30:35.303 に答える
2

タグを付けたのでSQL Server、とを利用しCommon Table ExpressionてくださいWindow Functions

;WITH filteredList
AS
(
  SELECT OrderID
  FROM tableName
  WHERE Type IN ('Food','Beverage')
  GROUP BY OrderID
  HAVING COUNT(DISTINCT Type) = 2
),
greatestList
AS
(
    SELECT  a.OrderID, a.Name, a.Type, a.Price,
            DENSE_RANK() OVER (PARTITION BY a.OrderID
                                ORDER BY a.Price DESC) rn
    FROM tableName  a
          INNER JOIN filteredList b
              ON a.OrderID = b.OrderID
    WHERE a.Type = 'Beverage'
)
SELECT  OrderID, Name, Type, Price
FROM    greatestList
WHERE   rn = 1
于 2013-01-18T11:22:22.637 に答える
1

Sql-Server 2005以降を使用している場合は、CTEwithDENSE_RANK関数を使用できます。

WITH CTE 
     AS (SELECT orderid, 
                name, 
                type, 
                price, 
                RN = Dense_rank() 
                       OVER ( 
                         PARTITION BY orderid 
                         ORDER BY CASE WHEN type='Beverage' THEN 0 ELSE 1 END ASC 
                         , price DESC) 
         FROM   dbo.tablename t 
         WHERE  EXISTS(SELECT 1 
                       FROM   dbo.tablename t2 
                       WHERE  t2.orderid = t.orderid 
                              AND type = 'Food') 
         AND    EXISTS(SELECT 1 
                       FROM   dbo.tablename t2 
                       WHERE  t2.orderid = t.orderid 
                              AND type = 'Beverage')) 
SELECT orderid, 
       name, 
       price 
FROM   CTE
WHERE  rn = 1 

DENSE_RANK同じ最高価格のすべての注文が必要な場合、および1つが必要な場合に使用しROW_NUMBERます。

DEMO

于 2013-01-18T11:24:25.307 に答える