Existe-t-il un moyen pour que cette sélection récupère les mêmes résultats avec une seule recherche?

8

Est-il possible de récupérer les mêmes données que les suivantes avec une seule recherche ou analyse, soit en modifiant la requête, soit en influençant la stratégie de l'optimiseur?

Le code et le schéma similaires sont actuellement sur SQL Server 2014.

entrez la description de l'image ici

Script de repro. Installer:

USE tempdb;
GO
IF OBJECT_ID('dbo.TestUpload', 'U') IS NOT NULL 
  DROP TABLE dbo.TestUpload; 


CREATE TABLE dbo.TestUpload(
    JobRunId bigint NOT NULL,
    ThingAName nvarchar(255) NOT NULL,
    ThingAType nvarchar(255) NOT NULL,
    ThingAGranularity nvarchar(255) NOT NULL,
    ThingBName nvarchar(255) NOT NULL,
    ThingBType nvarchar(255) NOT NULL,
    ThingBGranularity nvarchar(255) NOT NULL
);
CREATE CLUSTERED INDEX IX_JobRunId ON dbo.TestUpload (JobRunId);

GO

INSERT INTO dbo.TestUpload (JobRunId, ThingAName, ThingAType, ThingAGranularity, ThingBName, ThingBType, ThingBGranularity)
  VALUES (1, 'A', 'B', 'C', 'D', 'E', 'F');
GO 10

INSERT INTO dbo.TestUpload (JobRunId, ThingAName, ThingAType, ThingAGranularity, ThingBName, ThingBType, ThingBGranularity)
  VALUES (1, 'D', 'E', 'F', 'A', 'B', 'C');
GO 10

Requete:

DECLARE @JobRunID bigint = 1;

SELECT JobRunId,
  ThingAName AS Name, 
  ThingAType AS [Type], 
  ThingAGranularity AS Granularity
FROM dbo.TestUpload
WHERE JobRunId = @JobRunID
UNION
SELECT JobRunId,
  ThingBName AS Name, 
  ThingBType AS [Type], 
  ThingBGranularity AS Granularity
FROM dbo.TestUpload
WHERE JobRunId = @JobRunID;

Abattre:

IF OBJECT_ID('dbo.TestUpload', 'U') IS NOT NULL 
  DROP TABLE dbo.TestUpload;

Je pense que ce n'est probablement pas modélisé idéalement. J'essaie d'obtenir plus d'informations du développeur sur la façon dont le schéma a été choisi, mais je suis curieux de savoir s'il y a une astuce TSQL que je néglige car il sera plus facile de modifier la requête que le schéma.

James L
la source

Réponses:

6

J'essaierais cela mais je n'ai aucune idée si ce sera plus efficace. Vous avez besoin de DISTINCTpour supprimer les doublons, ce qui UNION ALLpourrait être plus approprié, pas besoin de deux opérations distinctes:

SELECT DISTINCT 
    JobRunId = @JobRunID, 
    d.*
FROM dbo.TestUpload
  CROSS APPLY 
    (   SELECT 
          ThingAName AS Name, 
          ThingAType AS [Type], 
          ThingAGranularity AS Granularity
      UNION                            -- or UNION ALL
        SELECT 
          ThingBName, 
          ThingBType, 
          ThingBGranularity
    ) AS d 
WHERE JobRunId = @JobRunID ;

UNION ALL plan:

Plan UNION ALL

UNION plan:

Plan UNION

ypercubeᵀᴹ
la source
3

Utiliser l'application croisée pour annuler le pivotement des colonnes dans les lignes

SELECT --DISTINCT most probably
  JobRunId,
  ut.Name, 
  ut.[Type], 
  ut.Granularity
FROM dbo.TestUpload
CROSS APPLY (
  SELECT ThingBName AS Name, 
  ThingBType AS [Type], 
  ThingBGranularity AS Granularity
  UNION ALL 
  SELECT ThingAName AS Name, 
  ThingAType AS [Type], 
  ThingAGranularity AS Granularity
  ) ut
WHERE JobRunId = @JobRunID
Serg
la source
1
Non, je pensais la même chose mais cela ne fonctionnerait pas. Pas même avec UNIONcar il y a des doublons qui doivent être supprimés.
ypercubeᵀᴹ
Vous voulez dire que le tri est inévitable?
Serg
1
Je veux dire que DISTINCTc'est nécessaire. Voir les données de James. Il y a une rangée avec A,B,C,-,-,-et une autre avec -,-,-,A,B,C. Les lignes résultantes, l'une des données A et l'autre des données B, sont identiques et doivent être supprimées. Même si le UNION ALLest remplacé par UNION, cela ne peut pas être évité. (et avec "ceci", je ne veux pas dire "trier", je veux dire l'opération "distincte". Il peut s'agir de trier ou de hacher, quelle que soit la méthode que l'optimiseur peut et choisit.)
ypercubeᵀᴹ