Question

Je cherche à reformuler la requête ci-dessous en une solution plus lisible et modifiable. La première moitié est identique à la seconde, à l'exception de la base de données interrogée (les noms des tables sont identiques).

  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

Cette requête correspond à la définition de DRY et m'appelle pour me contacter. -écrit, mais je ne sais pas comment!

MODIFIER : nous ne pouvons pas utiliser linq et nous souhaitons des résultats distincts; Je cherche à réduire la taille de la requête à la taille du fichier physique et non aux résultats renvoyés.

MODIFIER : la base de données sur laquelle j'interroge est une base de données ERP propriétaire. Restructurer ce n'est pas une option.

Était-ce utile?

La solution

Ceci est un modèle SQL assez standard. Parfois, il est facile de transférer par inadvertance des principes de code POOP / procédural tels que DRY vers SQL, mais ils ne sont pas nécessairement transférables.

Notez à quel point il est facile de gérer l'ensemble de la conception logique de la requête, par opposition à la recherche dans des sous-modules. Si l'une des sous-expressions comportait une colonne supplémentaire ou des colonnes inversées, elle resterait visible. Il s’agit d’une instruction SQL assez simple à utiliser comme unité d’exécution, où la désagréger l’embrouillerait.

Et lorsque vous déboguez, il est pratique de pouvoir utiliser l'option de mise en surbrillance du texte de l'éditeur pour exercer de manière sélective des parties de l'instruction - une technique qui n'existe pas dans le code de procédure. OTOH, il peut être compliqué d'essayer de tracer tous les éléments s'ils sont dispersés dans des vues, etc. Même les CTE peuvent rendre cela gênant.

Autres conseils

Je vais vous parler un peu ici et dire, en fonction des informations que vous nous avez fournies;

C'est aussi bon que ça va être

Un conseil en matière de performances que je vois immédiatement est d'utiliser UNION ALL au lieu de UNION sauf si vous souhaitez intentionnellement des enregistrements distincts. Un simple <=> élimine les doublons, ce qui prend du temps. <=> ne fait pas cela.

Vous pouvez le réécrire avec du SQL dynamique et une boucle mais je pense que le résultat serait pire. S'il y a suffisamment de doublons de code pour justifier l'approche SQL dynamique, alors je suppose que cela pourrait être justifié.

Sinon, avez-vous envisagé de déplacer la logique de la procédure stockée vers quelque chose comme LINQ? Pour beaucoup, ce n’est pas une option, je ne fais que demander.

Un dernier mot: résistez à la tentation de réparer ce qui n’est pas cassé pour le rendre plus propre. Si le nettoyage facilite la maintenance, la vérification, etc., alors allez-y.

Quel est le problème? Trop long? Trop répétitif?

Parfois, vous obtenez un mauvais SQL - vous ne pouvez pas y faire grand chose.

Je ne vois aucun moyen de le nettoyer, sauf si vous souhaitez utiliser des vues séparées, puis les unir ensemble.

Je vote pour des points de vue qui imposent un surcoût presque nul (OK, peut-être un petit coût de compilation mais ce devrait être tout). Ensuite, vos procs deviennent quelque chose de la forme

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

Je ne suis pas sûr de vouloir le condenser davantage, bien que la plupart des plateformes le tolèrent.

Sur le thème SQL dynamique - voici un exemple - vous ne savez pas s’il est meilleur. L'avantage est que vous n'avez qu'à écrire la liste SELECT une fois.

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

Si toutes vos procédures ressemblent à ceci, vous avez probablement un problème d'architecture.

Tous vos appels vers table2 ont-ils un seul champ utile? (et à cause de UNION, n’avons-nous qu’une rangée?)

Je souscris totalement à l'idée d'utiliser le code SQL dynamique paramétré et / ou la génération de code pour ce travail, allant même jusqu'à générer la liste de colonnes de manière dynamique à l'aide de INFORMATION_SCHEMA. Ce n'est pas exactement ce dont vous avez besoin, mais c'est un début (vous pouvez générer à partir d'une table de bases de données et de tables):

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)

En fonction du nombre de lignes renvoyées, il vaut peut-être mieux utiliser UNION ALL sur les sélections avec une requête distincte sélectionnée autour de celle-ci. J'ai déjà vu un problème similaire auparavant et mes plans d'exécution étaient différents pour les deux styles différents

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
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top