Pergunta

Eu estou olhando para refatorar o abaixo consulta para algo mais legível e modificável. A primeira metade é idêntico ao segundo, com exceção da base de dados consultada a partir de (nomes de tabela são os mesmos embora.)

  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

Esta consulta é a definição de DRY e está chamando-me ser re -written, mas não tenho idéia de como!

Editar : Não podemos usar LINQ e desejamos resultados distintos; Eu estou olhando para fazer a consulta menores em tamanho do arquivo físico, não em resultados retornados.

Editar : O banco de dados Eu estou consultando off é um banco de dados ERP proprietário. A reestruturação não é uma opção.

Foi útil?

Solução

Este é um padrão SQL bastante normal. Às vezes é fácil de OOP / Princípios Código de Processo transferência inadvisedly como DRY para SQL, mas eles não são necessariamente conceitos transferíveis.

Note como você pode facilmente Grokar o projeto lógico inteira da consulta, caça vs. através submódulos. Se um dos subexpressions tinha uma coluna extra, ou colunas revertida, ele iria ficar fora. Esta é basicamente uma instrução SQL muito simples de Grokar como uma unidade de execução, onde a desagregação seria confundir-lo.

E quando você estiver depuração, é útil para ser capaz de usar o texto do editor opção para peças de exercício seletivamente da declaração destacando - uma técnica que não existe no código processual. OTOH, ele pode ficar confuso tentando rastrear todas as peças se eles estão espalhados em vista etc. CTEs Até pode fazer este inconveniente.

Outras dicas

Vou sair em um membro aqui e dizer, com base nas informações que você nos deu;

que é tão bom quanto ele vai ficar

Uma dica de desempenho que eu vejo fora do bastão está usando UNION ALL vez de UNION menos que você queira intencionalmente registros distintos. Um simples UNION irá eliminar duplicatas que leva tempo. UNION ALL não faz isso.

Você poderia reescrevê-lo com SQL dinâmico e um loop, mas eu acho que o resultado seria pior. Se não houver código duplicado o suficiente para justificar a abordagem sql dinâmico, então eu acho que poderia ser justificada.

Como alternativa, você já pensou em se mudar a lógica fora do procedimento armazenado em algo como LINQ? Para muitos, esta não é uma opção, então eu só estou pedindo.

Uma nota final: resistir ao impulso de corrigir o que não está quebrado apenas para torná-la mais limpa. Se assessor limpeza vontade em manutenção, verificação, etc., em seguida, ir para ele.

Qual é o problema? Demasiado longo? Demasiado repetitivo?

Às vezes você tem SQL feio - não muito você pode fazer sobre ele.

Eu não vejo nenhuma maneira de limpá-lo, a menos que você deseja usar vistas separadas e, em seguida, união los juntos.

Eu voto para pontos de vista, que impõem quase o suficiente sobrecarga zero (OK, talvez um pequeno custo em tempo de compilação, mas que deveria ser todos). Em seguida, seus procs-se algo de forma

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

Eu não tenho certeza se eu gostaria de condensá-lo mais longe, embora eu espere a maioria das plataformas iria tolerar isso.

Sobre o tema dinâmico SQL - aqui está um exemplo - não tenho certeza se é melhor. O benefício é que você só tem que escrever a lista SELECT uma vez.

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

Se todos os seus procs olhar como este - você provavelmente tem um problema de arquitetura

.

São todas as suas chamadas para table2 apenas tem um campo útil? (E por causa da UNIÃO, acabam por ter apenas uma linha?)

I totalmente segundo a idéia de ir com SQL parametrizado dinâmico e / ou de geração de código para este trabalho, mesmo indo tão longe a ponto de gerar a lista de coluna dinamicamente usando INFORMATION_SCHEMA. Isso não é exatamente o que você precisa, mas é um começo (que você pode gerar de uma mesa de bases de dados e tabelas):

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)

Dependendo do número de linhas retornadas, você pode ser melhor usando UNION ALL nas seleciona com uma consulta distinta selecione em torno dele. Eu vi um problema semelhante antes e tinha diferentes planos de execução para os dois estilos diferentes

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
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top