Вопрос

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

  SELECT
    Column 1 AS c1,
    ...
    Column N AS cN
  FROM
    database1.dbo.Table1

UNION

  SELECT
    'Some String' as c1,
    ...
    NULL as cN
  FROM
    database1.dbo.Table2

UNION

  SELECT
    Column 1 AS c1,
    ...
    Column N AS cN
  FROM
    database2.dbo.Table1

UNION

  SELECT
    'Some String' as c1,
    ...
    NULL as cN
  FROM
    database2.dbo.Table2

Этот запрос является определением СУХОЙ и призывает меня переписать, но я понятия не имею, как это сделать!

Редактировать:Мы не можем использовать linq, и мы хотим получить отличные результаты;Я хочу уменьшить запрос по физическому размеру файла, а не по возвращаемым результатам.

Редактировать:База данных, к которой я запрашиваю, является проприетарной базой данных ERP.Реструктуризация - это не вариант.

Это было полезно?

Решение

Это довольно стандартный шаблон SQL.Иногда легко непреднамеренно перенести принципы ООП / процедурного кода, такие как DRY, в SQL, но они не обязательно являются переносимыми концепциями.

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

И когда вы отлаживаете, удобно иметь возможность использовать опцию выделения текста редактора для выборочного использования частей инструкции - техника, которая не существует в процедурном коде.OTOH, это может привести к путанице при попытке отследить все фрагменты, если они разбросаны по видам и т.д.Даже CTE могут сделать это неудобным.

Другие советы

Здесь я собираюсь рискнуть и сказать, основываясь на информации, которую вы нам предоставили;

Это настолько хорошо, насколько это возможно

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

Вы могли бы переписать его с помощью динамического SQL и цикла, но я думаю, что результат был бы хуже.Если существует достаточно повторяющегося кода, чтобы оправдать подход dynamic sql, то, я думаю, это может быть оправдано.

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

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

В чем проблема?Слишком долго?Слишком однообразно?

Иногда вы получаете некрасивый SQL - с этим мало что можно поделать.

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

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

SELECT * FROM database1.view1
UNION
SELECT * FROM database1.view2
UNION
SELECT * FROM database2.view1
UNION
SELECT * FROM database2.view2

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

По теме Dynamic SQL - вот пример - не уверен, что это лучше.Преимущество в том, что вам нужно написать список ВЫБОРА только один раз.

DECLARE @Select1 varchar(1000)
DECLARE @Select2 varchar(1000)

DECLARE @SQL varchar(4000)


SET @Select1 = 'SELECT
    Column 1 AS c1,
    ...
    Column N AS cN'


SET @Select2 = 'SELECT
    ''Some String'' as c1,
    ...
    NULL as cN'


SET @SQL = @Select1 + ' FROM database1.dbo.Table1 '

SET @SQL = @SQL + ' UNION ' + @Select2 + ' FROM database1.dbo.Table2 '

SET @SQL = @SQL + ' UNION ' + @Select1 + ' FROM database2.dbo.Table1 '

SET @SQL = @SQL + ' UNION ' + @Select2 + ' FROM database2.dbo.Table2 '


EXEC @SQL

Если все ваши процедуры выглядят подобным образом - вероятно, у вас архитектурная проблема.

Все ли ваши вызовы table2 содержат только одно полезное поле?(и из-за ОБЪЕДИНЕНИЯ в итоге получается только одна строка?)

Я полностью поддерживаю идею перехода к параметризованному динамическому SQL и / или генерации кода для этой работы, даже заходя так далеко, что генерирую список столбцов динамически, используя INFORMATION_SCHEMA.Это не совсем то, что вам нужно, но это начало (вы могли бы сгенерировать таблицу баз данных и таблиц):

DECLARE @template AS varchar(MAX)
SET @template = 'SELECT {@column_list} FROM {@database_name}.dbo.{@table_name}'
DECLARE @column_list AS varchar(MAX)

SELECT @column_list = COALESCE(@column_list + ',', '') + COLUMN_NAME
FROM database1.dbo.INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = @table_name
ORDER BY ORDINAL_POSITION

DECLARE @sql AS varchar(MAX)
SET @sql = @template
SET @sql = REPLACE(@sql, '{@column_list}', @column_list)
SET @sql = REPLACE(@sql, '{@database_name}', @database_name)
SET @sql = REPLACE(@sql, '{@table_name}', @table_name)

В зависимости от количества возвращаемых строк, возможно, вам лучше всего использовать UNION ALL для selects с запросом select distinct вокруг него.Я уже сталкивался с подобной проблемой раньше, и у меня были разные планы выполнения для двух разных стилей

SELECT DISTINCT subquery.c1, subquery.cN
FROM
(
SELECT Column 1 AS c1, Column N AS cN FROM database1.dbo.Table1
UNION ALL
SELECT 'Some String' as c1, NULL as cN FROM database1.dbo.Table2
UNION ALL
SELECT Column 1 AS c1, Column N AS cN FROM database2.dbo.Table1
UNION ALL
SELECT 'Some String' as c1, NULL as cN FROM database2.dbo.Table2
) subquery
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top