1

1 つのテーブルと 2 つの列を含む検索クエリがあります。

Select * 
from Gecoserv _a 
where _a.typeOfEcosystem IN (:typeNameList) 
    AND _a.service IN (:serviceNameList)

動作しますが、望んでいた結果が得られません

まあ言ってみれば:

typeNameList = { Freshwater, Saltwater, Dunes }
serviceNameList = {Habitat, Food, Recreation }

グリッドに単一の組み合わせ (淡水 - 生息地、海水 - 食品、砂丘 - レクリエーションなど) のみを表示したいのですが、他の組み合わせ (例: 淡水 - レクリエーション) も表示します。

言い換えれば:クエリの結果が表示されます

[0,0],[0,1],[0,2],
[1,0],[1,1],[1,2],
[2,0],[2,1],[2,2].

しかし、私が見たいのは : だけ[0,0],[1,1],[2,2]です。

クエリの最後に何かを追加する必要があることはわかっています。私は多くのことを試しましたが、完璧な解決策を見つけることができませんでした。

それを手伝ってくれる人はいますか?

よろしく、

メリー

4

2 に答える 2

0

これがあなたが持っている唯一の情報であるとき、これはできないと思います。パラメータの値間の関係は、リスト内の位置です。SQL でこれらの位置を関連付けたり保持したりするオプションはありません。

sql-statement の作成にどのような影響がありますか?

コード内のリストを繰り返し処理し、SQL を動的に作成できる場合は、次のような解決策にたどり着くことができます。

SELECT * FROM Gecoserv 
  WHERE typeOfEcosystem = 'Freshwater' AND service = 'Habitat'
UNION
SELECT * FROM Gecoserv 
  WHERE typeOfEcosystem = 'Freshwater' AND service = 'Food'
UNION
...

これをパラメータ化する方法の例については、この回答をご覧ください。

別の方法: 文字列の分割

あなたの主な問題は、リスト内のパラメーターの「ランク」/「位置」を保持することです。これは、リストを文字列に置き換えて分割することで実行できます。

sql で文字列を分割するこの例を使用しました。

結果のクエリ (この Fiddleで作成) は次のようになります。

DECLARE 
  @ecoSystems varchar(100) = 'Freshwater,Saltwater,Dunes',
  @services varchar(100) = 'Habitat,Food,Recreation',
  @separator char(1) = ','

SELECT
  [g].[id],
  [g].[typeOfEcoSystem],
  [g].[service]
FROM [dbo].[Split](@separator, @ecoSystems) [e]
INNER JOIN [dbo].[Split](@separator, @services) [s] 
  ON [e].[position] = [s].[position]
INNER JOIN [Gecoserv] [g] 
  ON [e].[part] = [g].[typeOfEcoSystem]
    AND [s].[part] = [g].[service]
ORDER BY [id] ASC

これはあなたのシナリオで機能しますか? (答え: はい、ほとんど...)

そして最後に機能なし

DECLARE 
  @ecoSystems varchar(100) = 'Freshwater,Saltwater,Dunes',
  @services varchar(100) = 'Habitat,Food,Recreation',
  @separator char(1) = ',';

WITH [EcoSystemsAndServices]([posE], [startE], [endE], [posS], [startS], [endS])
AS 
(
  SELECT 
    1, 
    1, 
    CHARINDEX(@separator, @ecoSystems),
    1, 
    1, 
    CHARINDEX(@separator, @services)
  UNION ALL
  SELECT 
    [posE] + 1, 
    [endE] + 1, 
    CHARINDEX(@separator, @ecoSystems, [endE] + 1),
    [posS] + 1, 
    [endS] + 1, 
    CHARINDEX(@separator, @services, [endS] + 1)
  FROM [EcoSystemsAndServices]
  WHERE [endE] > 0
)


SELECT 
  [g].[id],
  [g].[typeOfEcoSystem],
  [g].[service]
FROM [Gecoserv] [g]
INNER JOIN [EcoSystemsAndServices] [ess] 
  ON [g].[typeOfEcoSystem] = SUBSTRING(@ecoSystems, 
                                        [startE], 
                                        CASE WHEN [endE] > 0 THEN [endE] - [startE] ELSE 100 END)
    AND [g].[service] = SUBSTRING(@services, 
                                  [startS], 
                                  CASE WHEN [endS] > 0 THEN [endS] - [startS] ELSE 100 END)
ORDER BY [id] ASC
于 2013-01-17T21:38:16.803 に答える
0

バッキング スキーマやデータベース メーカーさえなければ、私の回答では、セットアップについていくつかの仮定を立てる必要があります。

仮説

これは非常にデカルト積のように聞こえます。問題の核心は、 IN 句が互いに独立していることです。したがって、1 つのレコードで両方の条件を満たすことができますが、結果セットで見たいものにはなりません。例として、次のようなレコードがあるとします。

id   name          typeOfEcosystem  service
--   ------------  ---------------  ----------
 1   myEcoService  Freshwater       Recreation

現在書かれているように、クエリは最初に typeOfEcosystem (Freshwater) を取得し、それがリストにあるかどうかを確認します。 結果: TRUE

次に、クエリはサービス (Recreation) を取得し、それが 2 番目のリストにあるかどうかを確認します。再び、値が見つかりました。 結果: TRUE

すべての条件が true と評価されるため、行は最終的な結果セットに含まれます。

解決

複数列の IN 句が必要なように思えます。最終的な解決策には単一の IN キーワードのみが含まれる必要があるため、これはあなたの試みとは異なることに注意してください。さて、クエリの正確な形式は、データベースとそれが提供するものに大きく依存します. SQL 準拠のデータベースで機能するソリューションは、文字列操作を使用することです。大まかな例は次のとおりです。

Select * 
  from Gecoserv _a 
 where _a.typeOfEcosystem || '-' || _a.service IN ('Freshwater-Habitat', 'Saltwater-Food', 'Dunes-Recreation')

この例では、'||' 連結されていると見なされます。これは非常に移植性がありますが、遅いです。この問題はよりエレガントに取り組むことができますが、正確な解決策は特定のデータベースと要件に大きく依存します。たとえば、Oracle の複数列 in 句は次のように単純です。

Select * 
  from Gecoserv _a 
 where (_a.typeOfEcosystem, _a.service) IN (('Freshwater', 'Habitat'), ('Saltwater', 'Food'), ('Dunes', 'Recreation'));

これらのソリューションが DBMS でうまく機能するようにするには、これらのソリューションをマッサージする必要がある場合があります。さらなるテクニック (そして昔ながらの読み物) は、次の場所にあります。

  1. IN句のSQL複数列

  2. SQLite を使用して列の組み合わせが繰り返されるレコードを選択する

于 2013-01-17T21:42:12.690 に答える