Объединение данных из 2 таблиц в один динамический запрос - PullRequest
0 голосов
/ 16 ноября 2011

У меня есть две таблицы:

table 1
id    item     itemType 
-----------------------
1     book1    1
2     book2    1
3     laptop1  2

table 2
id    itemId    name    value
------------------------------------------
1     1         author  enid blyton
2     1         title   five 1
3     2         author  enid blyton
4     2         title   five 2
5     3         cpu     i7-940
6     3         ram     4 GB
7     3         vcard   nvidia quadro

Когда я запрашиваю с фильтром itemType = 1, результат должен быть:

query 1
id    item    author          title
--------------------------------------------------------
1     book1   enid blyton     five 1
2     book2   enid blyton     five 2

и с фильтром itemType = 2

query 2
id    item       cpu       ram        vcard
----------------------------------------------
1     laptop1    i7-940    4 GB       nvidia quadro

и без фильтра

query 3
id    item    author          title      cpu       ram         vcard
---------------------------------------------------------------------------
1     book1   enid blyton     five 1
2     book2   enid blyton     five 2
1     laptop1                            i7-940    4 GB        nvidia quadro

Причина, по которой я использую таблицу 2, заключается в том, что параметр каждого itemType создается во время полета, поэтому невозможно получить таблицу, как в запросе 3.

На данный момент я могу решить эту проблему в C #, программно перестроив таблицу (используя много вызовов linq).При небольшом размере таблицы 1 (1К строк) и 2 (10К строк) производительность остается хорошей, но теперь размер таблицы 1 уже превышает 100К строк, а таблицы 2 - более 1М строк, а производительность очень высока.low.

Существует ли какая-либо функция, использующая SQL-запрос, которая может решить эту проблему?

Ответы [ 2 ]

1 голос
/ 16 ноября 2011

Я предлагаю запустить запрос, чтобы вернуть все возможные имена из таблицы2 для указанного типа элемента, например:

select distinct name
from table2 t2
where exists (select null
              from table1 t1
              where t1.itemtype = @itemtype and
                    t1.id = t2.item_id)

В C # объединить имена в одну строку, разделенную запятыми, а затем создать новуюСтрока запроса, аналогичная ответу Ливена, примерно так:

SELECT  t1.item
        , t2.*
FROM    table1 t1
        INNER JOIN (SELECT  *
                    FROM    (SELECT  itemId,
                                     name,
                                     value 
                             FROM    table2) s
                            PIVOT (MAX(Value) 
                                   FOR name IN (/*insert names string here*/)) p
                   ) t2 ON t2.itemId = t1.Id
WHERE t1.itemtype = @itemtype;

(со строкой имен, заменяющей комментарий в скобках).

Кстати, по возможности, я предлагаю отделить имена от Таблицы2 в отдельную таблицу поиска, например, так:

name_table
----------
name_id
name
itemtype

- это будет означать, что первый запрос будет запрашивать только небольшую таблицу поиска, а не всю таблицу 2;его также можно использовать для согласованности значений имени при вводе данных.

1 голос
/ 16 ноября 2011

Не совсем динамический, но , если все ваши имена известны заранее , вы можете использовать PIVOT для извлечения ваших данных.

PIVOT вращает табличное выражение, поворачивая уникальные значения из одного столбца в выражении на несколько столбцов в выводе, и выполняет агрегацию, где они требуются на любой оставшийся значения столбца, которые требуются в конечном выводе.

Оператор SQL

SELECT  t1.Id
        , t1.item
        , t2.author
        , t2.title
        , t2.cpu
        , t2.ram
        , t2.vcard
FROM    table1 t1
        INNER JOIN (        
          SELECT  *
          FROM    (
                    SELECT  itemId
                            , name
                            , value 
                    FROM    table2
                  ) s
                  PIVOT (
                    MAX(Value) 
                    FOR name IN (title, author, cpu, ram, vcard)
                  ) p
        ) t2 ON t2.itemId = t1.Id

Тестовый скрипт

;WITH table1 (id, item, itemtype) AS (
    SELECT 1, 'book1', 1
    UNION ALL SELECT 2, 'book2', 1
    UNION ALL SELECT 3, 'laptop1', 2
)
, table2 (id, itemId, name, value) AS (
    SELECT 1, 1, 'author', 'enid blyton'
    UNION ALL SELECT 2, 1, 'title', 'five 1'
    UNION ALL SELECT 3, 2, 'author', 'enid blyton'
    UNION ALL SELECT 4, 2, 'title', 'five 2'
    UNION ALL SELECT 5, 3, 'cpu', 'i7 940'
    UNION ALL SELECT 6, 3, 'ram', '4 GB'
    UNION ALL SELECT 7, 3, 'vcard', 'nvidia quadro'
)
SELECT  t1.Id
        , t1.item
        , t2.author
        , t2.title
        , t2.cpu
        , t2.ram
        , t2.vcard
FROM    table1 t1
        INNER JOIN (        
          SELECT  *
          FROM    (
                    SELECT  itemId
                            , name
                            , value 
                    FROM    table2
                  ) s
                  PIVOT (
                    MAX(Value) 
                    FOR name IN (title, author, cpu, ram, vcard)
                  ) p
        ) t2 ON t2.itemId = t1.Id
...