Existe uma maneira de fazer essa seleção recuperar os mesmos resultados com uma única busca?

8

É possível recuperar os mesmos dados que os seguintes com uma única busca ou varredura, modificando a consulta ou influenciando a estratégia do otimizador?

Código e esquema semelhante a este estão atualmente no SQL Server 2014.

insira a descrição da imagem aqui

Repro script. Configuração:

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

Inquerir:

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;

Destruir:

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

Eu acho que isso provavelmente não é modelado idealmente. Estou tentando obter mais informações do desenvolvedor sobre como o esquema foi escolhido, mas estou curioso para saber se há um truque do TSQL que estou ignorando, pois será mais fácil alterar a consulta do que o esquema.

James L
fonte

Respostas:

6

Eu tentaria isso, mas não tenho idéia se será mais eficiente. Você precisa DISTINCTremover duplicatas, portanto, UNION ALLpode ser mais apropriado, sem a necessidade de duas operações distintas:

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 plano:

Plano UNION ALL

UNION plano:

Plano da UNIÃO

ypercubeᵀᴹ
fonte
3

Use a aplicação cruzada para desmembrar colunas em linhas

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
fonte
11
Não, eu pensei o mesmo, mas isso não funcionaria. Nem mesmo com UNIONas duplicatas que precisam ser removidas.
ypercubeᵀᴹ
Você quer dizer que a classificação é inevitável?
Serg
11
Quero dizer que DISTINCTé necessário. Veja os dados de James. Há uma linha com A,B,C,-,-,-e outra com -,-,-,A,B,C. As linhas resultantes, uma dos dados A e a outra dos dados B, são idênticas e precisam ser removidas. Mesmo se UNION ALLfor substituído UNION, isso não pode ser evitado. (e com "isto" Eu não quero dizer "sort", quero dizer a operação "distinta" Pode ser doen com classificação ou hash, qualquer método que o otimizador pode e opta por..)
ypercubeᵀᴹ