2017-01-18 12 views
-1

のための複雑なクエリを構築します。私は、role-name = Xの入力リストから、キーと値のペアに関連する少なくとも1つのプロパティを持つすべてのコンポーネントを見つけたいと思います。最後に、起点のコンポーネント(id,name,properties)に関するすべてのデータを収集したいと思います。
は、私は6つのテーブルを持っている多くのテーブル

誰かが適切なクエリを作成するのを手伝ってもらえますか?
編集:私は

SELECT c.id, c.name, p.name FROM components c 
INNER JOIN componentproperties cp ON cp.role = (SELECT id FROM propertyroles WHERE name = 'primary') AND cp.component_id = c.id 
INNER JOIN properties p ON p.key_id = (SELECT id FROM keys WHERE name IN (%1)) AND p.value_id = (SELECT id FROM values WHERE name IN (%2)) 
UNION ALL 
SELECT cp2.name FROM componentproperties cp2 WHERE cp2.id IN cp.id 
UNION ALL 
SELECT keys.name FROM keys WHERE keys.id IN %1 
UNION ALL 
SELECT values.name FROM values WHERE values.id IN %2 
ORDER BY c.name; 

PSを開始するcompletly見当がつかない。私の英語のために申し訳ありません!

+3

あなたは何かを試してみましたまだですか? SOは無料のコード作成サービスではありません。 –

+0

ええ、私は知っています。私は自分の投稿を編集しました。 –

答えて

1

これは、使用しているPostgreSQLのバージョンによっていくつかの方法があります。私はここで複数のサブクエリでそれを解決します。

Propertiesテーブルでは、プロパティの役割を指定しますが、それにはComponentPropertiesもあります。私はあなたが複数の場所に同じデータを持つことを望んでいないと仮定しているので、ここではソリューションではComponentPropertiesのrole_idは存在しないと仮定します。

最初の問題は、key:value-pairsのリストをどのように検索して検索できるようにするかです。

CREATE TEMP TABLE key_value_role AS (
    key text, 
    value text, 
    role text 
); 

そして、そのテーブル内のすべての値を挿入します。

一つの方法は、(一時的な)表を作成することです。

INSERT INTO key_value_role VALUES 
('Key 1', 'Value 1', 'Role 1'), 
('Key 2', 'Value 2', 'Role 1'), 
('Key 2', 'Value 3', 'Role 1'); 

一時テーブルであっても、すばやく乱雑になります。幸いVALUESは、スタンドアロンで使用することができます。

SELECT column1 as key, column2 as value, column3 as role 
FROM (
    VALUES 
    ('Key 1', 'Value 1', 'Role 1'), 
    ('Key 2', 'Value 2', 'Role 1'), 
    ('Key 2', 'Value 3', 'Role 1') 
) AS kvr 

あなたは> = 9.3あなたがシリアライズされたJSONの文字列としてデータを送信し、json_each_textとキーを反復処理することができますPostgreSQLの使用している場合:

SELECT *, 'Role 1'::text as role 
FROM json_each_text('{"Key 1":"Value 1", "Key 2":"Value 2"}') 

上記の例ではリテラル文字列を使用していますが、パラメータ化されたクエリを使用し、プログラムでJSON-serialization-stringを作成すると仮定します。

上記の方法の制限は、指定されたキーには1つの値しか持たないということです。おそらくそれで十分でしょうが、私は、各キーの複数の値を検索できる柔軟なソリューションを求めていました。

Postgresql> = 9.3にはjson_populate_recordsetという別の機能がありますが、基本タイプが必要です。基本型は、既存のテーブルかもしれないが、あなたはまた、使用するタイプを作成することができますタイプが指定されている場合

CREATE TYPE key_value_role as(
    key text, 
    value text, 
    role text 
); 

json_populate_recordsetを使用することができます。

SELECT * 
FROM json_populate_recordset(null::key_value_role,'[{"key":"Key 1", "value":"Value 1", "role":"Role 1"},{"key":"Key 2", "value":"Value 2", "role":"Role 1"}, {"key":"Key 2", "value":"Value 3", "role":"Role 1"}]') 

出力例:

key | value | role 
--------+------------+---------- 
"Key 1" | "Value 1" | "Role 1" 
"Key 2" | "Value 2" | "Role 1" 
"Key 2" | "Value 3" | "Role 1" 

これで、各キーに複数の値を設定し、同じクエリで異なる役割を検索することができます。

次の問題は、名前をidsに変換することです。あなたはあなたのIDのタイプを指定していません。私は整数を仮定した。

SELECT 
    Keys.id as key_id, Values.id as value_id, PropertyRoles.id as role_id, 
    Keys.name as key_name, Values.name as value_name, PropertyRoles.name as role_name 
FROM list 
    JOIN Keys ON (list.key = Keys.name) 
    JOIN Values ON (list.value = Values.name) 
    JOIN PropertyRoles ON (list.role = PropertyRoles.name) 

出力例:テーブルと

key_id | value_id | role_id | key_name | value_name | role_name 
--------+----------+---------+----------+------------+----------- 
     1 |  1 |  1 | "Key 1" | "Value 1" | "Role 1" 
     2 |  2 |  1 | "Key 2" | "Value 2" | "Role 1" 
     2 |  3 |  1 | "Key 2" | "Value 3" | "Role 1" 

は、上記の方法で作成したリストは、その後、IDSに名前の変換は次のように行うことができる、 listと呼ばれているものとします上記のプロパティに参加することができます:

SELECT Properties.id as property_id, Properties.name as property_name, kvr.* 
FROM Properties 
    JOIN (
    -- previous query here 
) AS kvr ON (Properties.key_id = kvr.key_id AND Properties.value_id = kvr.value_id AND Properties.role_id = kvr.role_id) 

出力例:

property_id | property_name  | key_id | value_id | role_id | key_name | value_name | role_name 
-------------+--------------------+--------+----------+---------+----------+------------+----------- 
      1 | "Property 01 k1v1r1" |  1 |  1 |  1 | "Key 1" | "Value 1" | "Role 1" 
      13 | "Property 13 k2v2r1" |  2 |  2 |  1 | "Key 2" | "Value 2" | "Role 1" 
      16 | "Property 16 k2v3r1" |  2 |  3 |  1 | "Key 2" | "Value 3" | "Role 1" 

そして、上記の表には、今ComponentPropertiesと結合することができます。

SELECT ComponentProperties.id as ComponentProperties_id, ComponentProperties.component_id, pkvr.* 
FROM ComponentProperties 
    JOIN (
    -- previous query here 
) AS pkvr ON (ComponentProperties.property_id = pkvr.property_id) 

出力例:

componentproperties_id | component_id | property_id | property_name  | key_id | value_id | role_id | key_name | value_name | role_name 
-----------------------+--------------+-------------+--------------------+--------+----------+---------+----------+------------+----------- 
         1 |   1 |   1 | "Property 01 k1v1r1" |  1 |  1 |  1 | "Key 1" | "Value 1" | "Role 1" 
         2 |   1 |   13 | "Property 13 k2v2r1" |  2 |  2 |  1 | "Key 2" | "Value 2" | "Role 1" 
         3 |   1 |   16 | "Property 16 k2v3r1" |  2 |  3 |  1 | "Key 2" | "Value 3" | "Role 1" 
         4 |   2 |   1 | "Property 01 k1v1r1" |  1 |  1 |  1 | "Key 1" | "Value 1" | "Role 1" 
         7 |   3 |   16 | "Property 16 k2v3r1" |  2 |  3 |  1 | "Key 2" | "Value 3" | "Role 1" 
         9 |   4 |   13 | "Property 13 k2v2r1" |  2 |  2 |  1 | "Key 2" | "Value 2" | "Role 1" 

そして最後に、コンポーネントとそれに参加する:

SELECT Components.name as component_name, Components.type as component_type, cpkvr.* 
FROM Components 
    JOIN (
    -- previous query here 
) AS cpkvr ON (Components.id = cpkvr.component_id) 

出力例:

component_name | component_type | componentproperties_id | component_id | property_id | property_name  | key_id | value_id | role_id | key_name | value_name | role_name 
----------------+----------------+------------------------+--------------+-------------+--------------------+--------+----------+---------+----------+------------+----------- 
"Component 1" | "Component type" |      1 |   1 |   1 | "Property 01 k1v1r1" |  1 |  1 |  1 | "Key 1" | "Value 1" | "Role 1" 
"Component 1" | "Component type" |      2 |   1 |   13 | "Property 13 k2v2r1" |  2 |  2 |  1 | "Key 2" | "Value 2" | "Role 1" 
"Component 1" | "Component type" |      3 |   1 |   16 | "Property 16 k2v3r1" |  2 |  3 |  1 | "Key 2" | "Value 3" | "Role 1" 
"Component 2" | "Component type" |      4 |   2 |   1 | "Property 01 k1v1r1" |  1 |  1 |  1 | "Key 1" | "Value 1" | "Role 1" 
"Component 3" | "Component type" |      7 |   3 |   16 | "Property 16 k2v3r1" |  2 |  3 |  1 | "Key 2" | "Value 3" | "Role 1" 
"Component 4" | "Component type" |      9 |   4 |   13 | "Property 13 k2v2r1" |  2 |  2 |  1 | "Key 2" | "Value 2" | "Role 1" 

これはjson_populate_recordsetを使用して、クエリ全体です:

-- Get components from matching properties 
SELECT Components.name as component_name, Components.type as component_type, cpkvr.* 
FROM Components 
    JOIN (
    -- Get component id from matching properties 
    SELECT ComponentProperties.id as ComponentProperties_id, ComponentProperties.component_id, pkvr.* 
    FROM ComponentProperties 
     JOIN (
     -- Get propety id and name of matching values 
     SELECT Properties.id as property_id, Properties.name as property_name, kvr.* 
     FROM Properties 
      JOIN (
      -- Convert key, value and role names to id 
      SELECT 
       Keys.id as key_id, Values.id as value_id, PropertyRoles.id as role_id, 
       Keys.name as key_name, Values.name as value_name, PropertyRoles.name as role_name 
      FROM 
       json_populate_recordset(null::key_value_role,'[{"key":"Key 1", "value":"Value 1", "role":"Role 1"},{"key":"Key 2", "value":"Value 2", "role":"Role 1"}]') 
       AS list 
       JOIN Keys ON (list.key = Keys.name) 
       JOIN Values ON (list.value = Values.name) 
       JOIN PropertyRoles ON (list.role = PropertyRoles.name) 
     ) AS kvr ON (Properties.key_id = kvr.key_id AND Properties.value_id = kvr.value_id AND Properties.role_id = kvr.role_id) 
    ) AS pkvr ON (ComponentProperties.property_id = pkvr.property_id) 
) AS cpkvr ON (Components.id = cpkvr.component_id) 
ORDER BY component_name, property_name 

そして、ここでは、私が使用したテストデータである:

CREATE TYPE key_value_role as(
    key text, 
    value text, 
    role text 
); 

create table Keys(
    id integer unique primary key, 
    name text unique 
); 

create table Values(
    id integer unique primary key, 
    name text unique 
); 
create table PropertyRoles(
    id integer unique primary key, 
    name text unique 
); 
create table Properties(
    id integer unique primary key, 
    name text, 
    key_id integer references Keys, 
    value_id integer references Values, 
    role_id integer references PropertyRoles 
); 
create table Components(
    id integer unique primary key, 
    name text unique, 
    type text 
); 
create table ComponentProperties(
    id integer unique primary key, 
    component_id integer references Components, 
    property_id integer references Properties, 
    unique (component_id, property_id) 
); 

INSERT INTO Keys values 
(1, 'Key 1'), 
(2, 'Key 2'), 
(3, 'Key 3'); 

INSERT INTO Values values 
(1, 'Value 1'), 
(2, 'Value 2'), 
(3, 'Value 3'); 

INSERT INTO PropertyRoles values 
(1, 'Role 1'), 
(2, 'Role 2'), 
(3, 'Role 3'); 

INSERT INTO Properties values 
(1, 'Property 01 k1v1r1', 1, 1, 1), 
(2, 'Property 02 k1v1r2', 1, 1, 2), 
(3, 'Property 03 k1v1r3', 1, 1, 3), 
(4, 'Property 04 k1v2r1', 1, 2, 1), 
(5, 'Property 05 k1v2r2', 1, 2, 2), 
(6, 'Property 06 k1v2r3', 1, 2, 3), 
(7, 'Property 07 k1v3r1', 1, 3, 1), 
(8, 'Property 08 k1v3r2', 1, 3, 2), 
(9, 'Property 09 k1v3r3', 1, 3, 3), 
(10, 'Property 10 k2v1r1', 2, 1, 1), 
(11, 'Property 11 k2v1r2', 2, 1, 2), 
(12, 'Property 12 k2v1r3', 2, 1, 3), 
(13, 'Property 13 k2v2r1', 2, 2, 1), 
(14, 'Property 14 k2v2r2', 2, 2, 2), 
(15, 'Property 15 k2v2r3', 2, 2, 3), 
(16, 'Property 16 k2v3r1', 2, 3, 1), 
(17, 'Property 17 k2v3r2', 2, 3, 2), 
(18, 'Property 18 k2v3r3', 2, 3, 3), 
(19, 'Property 19 k3v1r1', 3, 1, 1), 
(20, 'Property 20 k3v1r2', 3, 1, 2), 
(21, 'Property 20 k3v1r3', 3, 1, 3), 
(22, 'Property 20 k3v2r1', 3, 2, 1), 
(23, 'Property 20 k3v2r2', 3, 2, 2), 
(24, 'Property 20 k3v2r3', 3, 2, 3), 
(25, 'Property 20 k3v3r1', 3, 3, 1), 
(26, 'Property 20 k3v3r2', 3, 3, 2), 
(27, 'Property 20 k3v3r3', 3, 3, 3); 


INSERT INTO Components values 
(1, 'Component 1', 'Component type'), 
(2, 'Component 2', 'Component type'), 
(3, 'Component 3', 'Component type'), 
(4, 'Component 4', 'Component type'); 

INSERT INTO ComponentProperties values 
(1, 1, 1), 
(2, 1, 3), 
(3, 1, 5), 
(4, 2, 1), 
(5, 2, 5), 
(6, 2, 6), 
(7, 3, 1), 
(8, 4, 5), 
(9, 4, 6); 
+0

ええ、これは大きなことです!本当に詳細な説明に感謝します。私はこれを完全に理解するために長い道のりを進んでいます:) –

+0

これは初心者レベルのクエリではありませんが、それを小さな断片に分割すると理解しにくいはずはありません。あなたは学ぶでしょう。 :)以前は見たことのないJSON形式のデータがある「魔法」があります。あなたがクエリについて理解していない特別なことがあるかどうかを教えてください。私は説明しようとします。 – some

+0

@ geo-amateurところで、このような質問をすると、私の答えの最後の部分にあるように、テーブルを作成してテストデータを挿入するコマンドを提供することは素晴らしいことです。あなたの質問を更新する場合は、私の答えから関連する部分を自由にコピーしてください。 – some

関連する問題