2015-07-09 5 views
1

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

Скажем, у меня есть таблицы TableofValues, TableA, TableB и TableC, как показано ниже.

Можно ли присоединиться к соответствующей таблице на основе TableName в TableofValues, а затем выбрать поле на основе FieldName, где TableRowID = ID в объединенной таблице?

Это SQL Server 2008.

Пример набора таблиц:

enter image description here

Желательные Результаты:

enter image description here

+0

Да, оператор SQL может быть динамически сконструирован. Но точная помощь может быть предоставлена ​​только в том случае, если вы предоставите больше информации о том, чего вы пытаетесь достичь, сделав это. –

+1

Как уже говорилось в @WhirlMind, это будет * как-то возможно в том, как вы предложили, но, возможно, вам стоит подумать об изменении вашей табличной архитектуры, чтобы все данные собирались в одной таблице с дополнительным столбцом, идентифицирующим содержимое как принадлежащее 'tableA', 'tableB' или 'tableC'. Такой макет упростит ваше обслуживание данных в будущем. – cars10m

+0

I второй предыдущий оператор: повторение «TableA», «TableB» ... и имя столбца займет много места в базе данных, чтобы обеспечить мало. Я уже видел таблицы ссылок таким образом, что «id, table_id, table_row_id, value» выглядел похожим, а table_id ссылался на другую таблицу, описывающую таблицу (имена и столбцы). Однако некоторые приложения собирали информацию в одну таблицу. Обратите внимание, что я буду использовать UNION INNER JOIN вместо LEFT JOIN (или INNER JOIN UNION), чтобы поддерживать оптимальную производительность. – birdypme

ответ

0

Помимо того, что вы должны иметь очень хороший причина для этого, потому что это ОЧЕНЬ ПЛОХОЙ дизайн в противном случае, вы могли бы думать о VIEW с помощью SchemaBinding ,

Вам нужно будет создать VIEW для любого данного TableName. Это можно использовать в JOIN

1

Вы также можете достичь этого без динамического запроса. См. Следующий код:

-- Create Demo Data 
CREATE TABLE #TableOfValues(id int identity(1,1), value float, TableName nvarchar(30), FieldName nvarchar(30), TableRowId int) 

INSERT INTO #TableOfValues(value, TableName, FieldName, TableRowId) 
VALUES (1234.2,N'TableA',N'Customer',1), 
     (245.5,N'TableB',N'Cust',3), 
     (248.59,N'TableA',N'Customer',2), 
     (8526.36,N'TableC',N'Cstmer',1), 
     (224.15,N'TableB',N'Cust',5), 
     (148.98,N'TableC',N'Cstmer',2) 

CREATE TABLE #TableA(id int identity(1,1), Customer nvarchar(30)) 

INSERT INTO #TableA(Customer) 
VALUES(N'Bloggs'),(N'Smith'),(N'Jones') 

CREATE TABLE #TableB(id int identity(1,1), Cust nvarchar(30)) 

INSERT INTO #TableB(Cust) 
VALUES (N'Aother'),(N'NJONES'), (N'FBLOGGS'), (N'SMITH'), (N'BARTHUR') 

CREATE TABLE #TableC(id int identity(1,1), Cstmer nvarchar(30)) 

INSERT INTO #TableC(Cstmer) 
VALUES(N'Mr Fred Bloggs'),(N'Tony Smith') 

-- Your Part 
SELECT tov.id, tov.value, tov.TableName, tov.FieldName, tov.TableRowId, tabs.tabVal 
FROM #TableOfValues as tov 
INNER JOIN (
    SELECT N'TableA' as tabName, a.id, a.Customer as tabVal 
    FROM #TableA as a 
    UNION ALL 
    SELECT N'TableB' as tabName, b.id, b.Cust as tabVal 
    FROM #TableB as b 
    UNION ALL 
    SELECT N'TableC' as tabName, c.id, c.Cstmer as tabVal 
    FROM #TableC as c 
) as tabs 
    ON tov.TableName = tabs.tabName 
    AND tov.TableRowId = tabs.id 

-- Cleanup 
DROP TABLE #TableOfValues 
DROP TABLE #TableA 
DROP TABLE #TableB 
DROP TABLE #TableC 

Если вы хотите, вы можете добавить (если они не будут) индексы к таблицам. Это позволит повысить эффективность запросов, если вы ищете конкретные значения.

CREATE CLUSTERED INDEX [NCI_TableOfValues_id] 
ON #TableOfValues ([id]) 

CREATE CLUSTERED INDEX [NCI_TableA_id] 
ON #TableA ([id]) 

CREATE CLUSTERED INDEX [NCI_TableB_id] 
ON #TableB ([id]) 

CREATE CLUSTERED INDEX [NCI_TableC_id] 
ON #TableC ([id]) 

CREATE NONCLUSTERED INDEX [NCI_TableOfValues_TableName] 
ON #TableOfValues([TableName]) 
INCLUDE ([id],[value],[FieldName],[TableRowId]) 

Помимо решения, дизайн стола плохой. Это еще больше улучшит вашу производительность SELECT.

+1

Если таблицы большие, это будет очень медленно ... – Shnugo

+0

Вы можете предварительно фильтровать строки, используя подзапрос, если это необходимо. Я изменил его на конструкцию «UNION ALL». Это выполнено за 10 секунд. на полном наборе результатов, который содержит 6.000.000 строк в результате. Ну, я думаю, что это достаточно быстро. :-D Если вы отфильтровываете определенное значение TableOfValues, оно будет немедленно найдено. – Ionic

+0

Вот почему я предложил связанный VIEW, но, возможно, OP будет доволен прагматичным подходом :-) – Shnugo

0

Вы также можете это сделать. Вы хотите объединить все строки от #TableA, #TableB и #TableC и добавить столбец, чтобы определить FieldName.

SELECT 
    Customer = FieldValue, 
    Value = v.value 
FROM #TableOfValues v 
LEFT JOIN (
    SELECT id, Customer AS FieldValue, 'Customer' AS FieldName FROM #TableA UNION ALL 
    SELECT id, Cust, 'Cust' FROM #TableB UNION ALL 
    SELECT id, Cstmer, 'Cst' FROM #TableC 
)t 
    ON v.FieldName = t.FieldName 
    AND v.TableRowId = t.id 
Смежные вопросы