1

解決できないSQLステートメントがあります...結合で「OR」を実行する方法がわかりません。実際、私が参加するべきかどうかはわかりません...これまでのところ次のようになっています。

SELECT o.* FROM dbo.Orders o
    INNER JOIN dbo.Transactions t1 ON t1.OrderId = o.OrderId
                                  AND t1.Code = 'TX33'
    INNER JOIN dbo.Transactions t2 ON t2.OrderId = o.OrderId
                                  AND t2.Code = 'TX34'
WHERE o.PurchaseDate NOT NULL

私はまだこれを実行していませんが、これにより、TX33とTX34の両方のトランザクションを持つ購入日を持つすべての注文が取得されると思います。これらのトランザクションの両方がない注文は表示されません(内部結合のため)。私が立ち往生している部分はこれです:

注文に次のいずれかが含まれていることも確認できる必要があります。

  • TX35およびTX36
  • TX37
  • TX38およびTX39

これらの追加条件の1つだけが必要です。そこにいる必要があるので、単純にINNERJOINを行うことはできません。通常のJOINを実行する場合、「OR」条件の1つ自体が「AND」条件ではない場合に機能させることができます(TX35 AND TX361つのJOIN条件として実行する方法もわかりませんTX38 AND TX39

4

4 に答える 4

3

WHERE選択ロジックは句に含まれている必要があります。おそらくこのようなもの:

SELECT o.* FROM dbo.Orders AS o, dbo.Transactions AS t1, dbo.Transactions AS t2
WHERE t1.OrderId = o.OrderId AND t2.OrderId = o.OrderId
AND o.PurchaseDate NOT NULL
AND (
  (t1.Code = 'TX33' AND t2.Code = 'TX34') OR 
  (t1.Code = 'TX35' AND t2.Code = 'TX36') OR 
  (t1.Code = 'TX37') OR 
  (t1.Code = 'TX38' AND t2.Code = 'TX39') 
)

4つの独立した選択基準が必要な場合は、次のようにJOIN4回テーブルを作成する必要があります。

SELECT o.* FROM dbo.Orders AS o, dbo.Transactions AS t1, dbo.Transactions AS t2
WHERE t1.OrderId = o.OrderId AND t2.OrderId = o.OrderId 
AND t3.OrderId = o.OrderId AND t4.OrderId = o.OrderId
AND o.PurchaseDate NOT NULL
AND (t1.Code = 'TX33' AND t2.Code = 'TX34')
AND ( 
  (t3.Code = 'TX35' AND t4.Code = 'TX36') OR 
  (t3.Code = 'TX37') OR 
  (t3.Code = 'TX38' AND t4.Code = 'TX39') 
)
于 2013-01-16T20:05:39.003 に答える
2

ON句に複雑な条件を含めることができます。aを使用するLEFT OUTER JOINと、句の奇数の場合(TX37)を処理できますWHERE

R節内のへの参照WHEREは、外部結合が内部結合に変換されないようにNULLを処理する必要があることに注意してください。

select L.*
  from dbo.Orders as L left outer join
    dbo.Orders as R on R.OrderId = L.OrderId and (
      ( L.Code = 'TX33' and R.Code = 'TX34' ) or
      ( L.Code = 'TX35' and R.Code = 'TX36' ) or
      ( L.Code = 'TX38' and R.Code = 'TX39' ) )
  where L.PurchaseDate is not NULL and ( L.Code = 'TX37' or R.Code is not NULL )

TX33、TX34 、およびその他のパタ​​ーンの1つ以上を含む注文のみが本当に必要な場合は、もう少し複雑です。とを使用group by L.OrderIdするとcount( L.OrderId )、たとえば、パターン間で2つ以上一致する注文を見つけることができます。それは次のようなものに近づき始めます:

declare @Orders as Table ( Id Int Identity, OrderId Int, Code VarChar(4), PurchaseDate Date )
insert into @Orders ( OrderId, Code, PurchaseDate ) values
  ( 1, 'TX37', GetDate() ),
  ( 2, 'TX37', GetDate() ), ( 2, 'FOO', GetDate() ),
  ( 3, 'TX33', GetDate() ), ( 3, 'TX34', GetDate() ),
  ( 4, 'TX33', GetDate() ), ( 4, 'TX34', GetDate() ), ( 4, 'TX37', GetDate() ),
  ( 5, 'TX33', GetDate() ), ( 5, 'TX34', GetDate() ), ( 5, 'TX35', GetDate() ),
    ( 5, 'TX36', GetDate() ),
  ( 6, 'TX33', GetDate() ), ( 6, 'TX34', GetDate() ), ( 6, 'TX35', GetDate() ),
    ( 6, 'TX36', GetDate() ), ( 6, 'TX37', GetDate() ),
  ( 7, 'TX38', GetDate() ), ( 7, 'TX39', GetDate() ), ( 7, 'TX35', GetDate() ),
    ( 7, 'TX36', GetDate() ), ( 7, 'TX37', GetDate() )

select * from (
  select L.OrderId,
    Max( case when L.Code = 'TX33' and R.Code = 'TX34' then 1 else 0 end ) as Mandatory,
    Count( L.OrderId ) as Matches
    from @Orders as L left outer join
      @Orders as R on R.OrderId = L.OrderId and (
        ( L.Code = 'TX33' and R.Code = 'TX34' ) or
        ( L.Code = 'TX35' and R.Code = 'TX36' ) or
        ( L.Code = 'TX38' and R.Code = 'TX39' ) )
    where L.PurchaseDate is not NULL and ( L.Code = 'TX37' or R.Code is not NULL )
    group by L.OrderId ) as Arnold
  where Mandatory = 1 and Matches > 1
于 2013-01-16T20:24:02.183 に答える
2
SELECT o.* 
FROM dbo.Orders o
WHERE EXISTS ( SELECT *   FROM dbo.Transactions t1 
               WHERE t1.OrderId = o.OrderId   AND t1.Code = 'TX33'
             )
  AND EXISTS ( SELECT *   FROM dbo.Transactions t2 
               WHERE t2.OrderId = o.OrderId   AND t2.Code = 'TX34'
             )
  AND
    (     EXISTS ( SELECT *   FROM dbo.Transactions t1 
                   WHERE t1.OrderId = o.OrderId   AND t1.Code = 'TX35'
                 )
      AND EXISTS ( SELECT *   FROM dbo.Transactions t2 
                   WHERE t2.OrderId = o.OrderId   AND t2.Code = 'TX36'

    OR  EXISTS ( SELECT *   FROM dbo.Transactions t 
                 WHERE t.OrderId = o.OrderId    AND t.Code = 'TX37'
               )

    OR    EXISTS ( SELECT *   FROM dbo.Transactions t1 
                   WHERE t1.OrderId = o.OrderId   AND t1.Code = 'TX38'
                 )
      AND EXISTS ( SELECT *   FROM dbo.Transactions t2 
                   WHERE t2.OrderId = o.OrderId   AND t2.Code = 'TX39'
                 )
    ) ;

次のように書くこともできます。

SELECT o.* 
FROM dbo.Orders o
  JOIN
    ( SELECT OrderId
      FROM dbo.Transactions
      WHERE Code IN ('TX33', 'TX34', 'TX35', 'TX36', 'TX37', 'TX38', 'TX39')
      GROUP BY OrderId
      HAVING COUNT(DISTINCT CASE WHEN Code = 'TX33' THEN Code END) = 1
         AND COUNT(DISTINCT CASE WHEN Code = 'TX34' THEN Code END) = 1
         AND ( COUNT(DISTINCT 
                     CASE WHEN Code IN ('TX35', 'TX36') THEN Code END) = 2
            OR COUNT(DISTINCT CASE WHEN Code = 'TX37' THEN Code END) = 1
            OR COUNT(DISTINCT 
                     CASE WHEN Code IN ('TX38', 'TX39') THEN Code END) = 2
             ) 
    ) t
    ON t.OrderId = o.OrderId ;
于 2013-01-16T21:38:49.660 に答える
-1

しばらくそれをいじった後、私は次のクエリであなたの目標を達成したと思います:

SELECT * FROM (
    SELECT o.*, t3.Code as t3 FROM dbo.Orders o
        INNER JOIN dbo.Transactions t1 ON t1.OrderId = o.OrderId
                                      AND t1.Code = 'TX33'
        INNER JOIN dbo.Transactions t2 ON t2.OrderId = o.OrderId
                                      AND t2.Code = 'TX34'
        INNER JOIN dbo.Transactions t3 ON t3.OrderId = o.OrderId
                                      AND (
                                           t3.Code = 'TX35' OR 
                                           t3.Code = 'TX37' OR
                                           t3.Code = 'TX38'
                                          )
    ) WHERE t3 = 'TX37'
        OR (t3 = 'TX36' AND EXISTS (SELECT t.Code FROM dbo.Transactions t WHERE t.OrderId = o.OrderId AND t.Code = 'TX36'))
        OR (t3 = 'TX38' AND EXISTS (SELECT t.Code FROM dbo.Transactions t WHERE t.OrderId = o.OrderId AND t.Code = 'TX39'))

内部SELECTは、コードTX34、TX35、およびTX35、TX37、またはTX38のいずれかを持つトランザクションにリンクされた注文のみを返す必要があります。この最後のコードのコピーを結果に保持します。

次に、3番目のコードがTX37(これ以上の条件は不要)である注文、または残りのコードが関連付けられている注文を保持することにより、リストをさらに絞り込む必要があります。

このアプローチは、最初にフィルタリングせずにTransactionsテーブルに4回参加するよりもパフォーマンスが優れていると思います。O*(T+T+T)*(T+T) = 6*O*T^2つまり、反復が必要ですが、4つの非フィルター結合アプローチではO*T*T*T*T = O*T^4反復が必要です。

于 2013-01-16T20:03:55.227 に答える