Как запросить несколько таблиц SQL для конкретной пары ключ-значение? - PullRequest
1 голос
/ 19 сентября 2008

Ситуация: PHP-приложение с несколькими устанавливаемыми модулями создает новую таблицу в базе данных для каждого в стиле mod_A, mod_B, mod_C и т. Д. У каждого есть столбец section_id.

Теперь я ищу все записи для определенного section_id, и я надеюсь, что есть другой способ, кроме «Выбрать * из mod_a, mod_b, mod_c ... mod_xyzzy, где section_id = value» ... или, что еще хуже используя отдельный запрос для каждого модуля.

Ответы [ 8 ]

1 голос
/ 19 сентября 2008

У меня есть два предложения.

  1. Возможно, вам нужно объединить все свои таблицы. Если все они содержат одинаковую структуру, то почему бы не иметь одну «главную» таблицу модулей, которая просто добавляет один новый столбец, идентифицирующий модуль («A», «B», «C», ....)

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

    В этом предложении предполагается, что ваш запрос в столбце section_id, который вы упомянули, является сверхкритическим для быстрого поиска. Одним запросом вы получаете всю общую информацию, а вторым - любую конкретную информацию, если она вам нужна. (И вы можете этого не сделать - например, если вы пытаетесь проверить существование раздела, то достаточно найти его в общей таблице)

  2. В качестве альтернативы вы можете добавить еще одну таблицу, которая сопоставляет section_id с модулями, в которых они находятся.

    section_id | module
    -----------+-------
          1    |  A
          2    |  B
          3    |  A
         ...   | ...
    

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

    Вы можете расширить эту таблицу другими столбцами и индексами этих столбцов, если вам нужно искать другие столбцы, общие для всех модулей.

    Этот метод имеет определенный недостаток, заключающийся в дублировании данных.

1 голос
/ 19 сентября 2008

Если таблицы меняются со временем, вы можете встроить код своего решения в SP (псевдокод - вам нужно будет заполнить):

SET @sql = ''

DECLARE CURSOR FOR
SELECT t.[name] AS TABLE_NAME
FROM sys.tables t
WHERE t.[name] LIKE 'SOME_PATTERN_TO_IDENTIFY_THE_TABLES'

- или это

DECLARE CURSOR FOR
SELECT t.[name] AS TABLE_NAME
FROM TABLE_OF_TABLES_TO_SEACRH t

START LOOP

IF @sql <> '' SET @sql = @sql + 'UNION ALL '
SET @sql = 'SELECT * FROM [' + @TABLE_NAME + '] WHERE section_id=value '

END LOOP

EXEC(@sql)

Я иногда использовал эту технику, когда просто не существует очевидного способа сделать ее будущей без динамического SQL.

Примечание: В вашем цикле вы можете использовать трюк распространения COALESCE / NULL и оставить строку как NULL перед циклом, но это не так ясно, если вы не знакомы с идиомой:

SET @sql = COALESCE(@sql + ' UNION ALL ', '')
    + 'SELECT * FROM [' + @TABLE_NAME + '] WHERE section_id=value '
1 голос
/ 19 сентября 2008

А как же?

SELECT * FROM mod_a WHERE section_id=value
UNION ALL
SELECT * FROM mod_b WHERE section_id=value
UNION ALL
SELECT * FROM mod_c WHERE section_id=value
0 голосов
/ 20 сентября 2008

Опция со стороны базы данных будет состоять в том, чтобы создать представление UNION ALL из различных таблиц. Когда вы добавляете таблицу, вам необходимо добавить ее в представление, но в противном случае она будет выглядеть как одна таблица.

CREATE VIEW modules AS (
    SELECT * FROM mod_A
    UNION ALL 
    SELECT * FROM mod_B
    UNION ALL 
    SELECT * FROM mod_C
);

select * from modules where section_id=value;
0 голосов
/ 20 сентября 2008
SELECT * FROM (
    SELECT * FROM table1
    UNION ALL
    SELECT * FROM table2
    UNION ALL
    SELECT * FROM table3
) subQry
WHERE field=value
0 голосов
/ 19 сентября 2008

Ну, есть только так много способов агрегировать информацию из нескольких таблиц. Вы можете присоединиться, как вы упомянули в своем примере, или вы можете запустить несколько запросов и объединить их вместе, как в ответе Боржаба. Я не знаю, была бы ли вам полезна идея создания таблицы, которая пересекает все таблицы модулей, но если бы section_id был на такой таблице, вы бы могли получить все из одного запроса. В противном случае, я аплодирую вашей лени, но боюсь сказать, я не вижу способа сделать эту работу более легкой:)

0 голосов
/ 19 сентября 2008

Возможно, некоторая дополнительная информация поможет, но, похоже, у вас уже есть решение. Вам придется выбрать из всех таблиц с section_id. Вы можете использовать объединения вместо списка таблиц, объединяя по section_id. Например

select a.some_field, b.some_field.... 
from mod_a a
inner join mod_b b on a.section_id = b.section_id
...
where a.section_id = <parameter>

Вы также можете упаковать это как представление. Также обратите внимание на список полей вместо *, который я бы порекомендовал, если вы намеревались использовать *.

0 голосов
/ 19 сентября 2008

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

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

...