Альтернативы ИСПОЛЬЗОВАНИЮ в JOIN для SQL Server для исключения дублированных столбцов в объединенной таблице

SQL Server не предлагает ключевое слово USING в контексте JOIN,
ни он не предоставляет NATURAL JOIN.

Кроме того, явным образом (вручную) перечислены все столбцы (ссылка на другой дублированный вопрос), есть ли альтернатива получить таблицу, в которой столбцы, на которые я соединяюсь, которые имеют одинаковое имя в 2 соединенных таблицах, не дублируются?

В качестве промежуточного шага я попытался сохранить во временной таблице результат

SELECT INTO #MyTempTable * FROM tableA 
INNER JOIN tableB 
ON tableA.commonColumn = tableB.commonColumn;

Но я уже получаю сообщение об ошибке:

Имена столбцов в каждой таблице должны быть уникальными. Имя столбца "commonColumn" в таблице "#MyTempTable" указано более одного раза.

Ответ 1

Нет, нет. Единственный способ избежать этой ошибки в запросе SELECT INTO - это записать список столбцов после SELECT вместо SELECT *.

Ответ 2

Единственная альтернатива - избежать SELECT ing *:

TableA

foo | bar
---------

TableB

foo | baz
---------

При выборе * из обеих таблиц в итоге вы получите 2 столбца с именем foo, которые недопустимы в одной таблице.

Назовите выбранные столбцы с помощью уникальных имен, и это будет работать.

SELECT INTO #TableTemp t1.foo foo1, t1.bar, t2.foo foo2, t2.baz
FROM tableA t1
INNER JOIN tableB t2 ON t1.foo = t2.foo

Но пока вы на нем, не нужно вставлять общий столбец дважды (как t1.foo = t2.foo). Выберите только один из них:

SELECT INTO #TableTemp t1.foo, t1.bar, t2.baz
FROM tableA t1
INNER JOIN tableB t2 ON t1.foo = t2.foo

РЕДАКТОР: Как сказал Филип Келли, эта проблема возникает только при попытке сохранить набор результатов в таблицу. Пока вы только выбираете данные, все работает отлично с повторяющимися именами столбцов.

Ответ 3

Я бы не рекомендовал это, но, чтобы ответить на ваш вопрос, вы могли бы создать функцию sql clause builder, которая автоматически создает псевдонимы столбцов для ваших отдельных таблиц с префиксом tablename (или настраивать его, если хотите)

declare @tableName nvarchar(100);


set @tableName = 'TestTable';

select @tableName + '.' + c.name + ' AS ' + @tableName + '_' + c.name
from sys.tables t
    inner join sys.columns c on c.object_id = t.object_id
where
    t.name = @tableName

Вывод для моей маленькой таблицы с двумя столбцами

TestTable.TestColumn1 AS TestTable_TestColumn1
TestTable.TestColumn2 AS TestTable_TestColumn2

Гипотетическое использование

declare @sql nvarchar(1000) = '';
set @sql = myClauseBuilder('TestTable');

set @sql = @sql + ',' + myClauseBuilder('TestTable2');

set @sql = @sql + ' FROM TestTable INNER JOIN TestTable2....(etc.)

exec @sql

Ответ 4

Это непросто. Но это возможно. Используя this, вы должны сначала создать два разделенных списка со всеми столбцами из двух таблиц, исключая общий столбец, к которому вы хотите присоединиться:

DECLARE @columnsA varchar(8000)

SELECT @columnsA = ISNULL(@columnsA + ', ','') + QUOTENAME(column_name)
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'tableA' AND COLUMN_NAME <> 'commonColumn'
ORDER BY ORDINAL_POSITION

DECLARE @columnsB varchar(8000)

SELECT @columnsB = ISNULL(@columnsB + ', ','') + QUOTENAME(column_name)
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'tableB' AND COLUMN_NAME <> 'commonColumn'
ORDER BY ORDINAL_POSITION

Затем вы будете использовать их для своего запроса, выбирая commonColumn только для одной из таблиц:

EXEC ('SELECT tableA.commonColumn, ' + @columnA + ', ' + @columnsB + ' FROM tableA INNER JOIN tableB ON tableA.commonColumn = tableB.commonColumn;')

Итак, есть хотя бы один способ сделать это.:) Это, по-видимому, также умеренно эффективно. Я не эксперт SQL, но я полагаю, что есть способ создать из этого функцию, возможно, одну функцию "выбрать все столбцы, но [...]", и одна функция, которая будет выполнять соединение как USING, будет сделать.


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

DECLARE @columnsB varchar(8000)

SELECT @columnsB = ISNULL(@columnsB + ', ','') + QUOTENAME(table_name) + '.' + QUOTENAME(column_name)
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'tableB' AND COLUMN_NAME <> 'commonColumn'
ORDER BY ORDINAL_POSITION

И запрос изменен на:

EXEC ('SELECT tableA.* ', ' + @columnsB + ' FROM tableA INNER JOIN tableB ON tableA.commonColumn = tableB.commonColumn;')