¿Hay alguna manera de hacer que esta selección recupere los mismos resultados con una sola búsqueda?

8

¿Es posible recuperar los mismos datos que los siguientes con una sola búsqueda o exploración, ya sea modificando la consulta o influyendo en la estrategia del optimizador?

El código y el esquema similar a este se encuentran actualmente en SQL Server 2014.

ingrese la descripción de la imagen aquí

Repro script. Preparar:

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

Consulta:

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;

Demoler:

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

Creo que esto probablemente no esté modelado idealmente. Estoy tratando de obtener más información del desarrollador sobre cómo se eligió el esquema, pero tengo curiosidad por saber si hay un truco TSQL que estoy pasando por alto, ya que será más fácil cambiar la consulta que el esquema.

James L
fuente

Respuestas:

6

Intentaría esto, pero no tengo idea si será más eficiente. Necesita DISTINCTeliminar los duplicados, por lo que UNION ALLpodría ser más apropiado, sin necesidad de dos operaciones 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 plan:

Plan UNION ALL

UNION plan:

Plan UNION

ypercubeᵀᴹ
fuente
3

Utilice la aplicación cruzada para desenredar columnas en filas

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
fuente
1
No, pensé lo mismo, pero esto no funcionaría. Ni siquiera con, UNIONya que hay duplicados que deben eliminarse.
ypercubeᵀᴹ
¿Quieres decir que el tipo es inevitable?
Serg
1
Quiero decir que DISTINCTse requiere. Ver los datos de James. Hay una fila con A,B,C,-,-,-y otra con -,-,-,A,B,C. Las filas resultantes, una de los datos A y la otra de los datos B, son idénticas y deben eliminarse. Incluso si UNION ALLse reemplaza con UNION, esto no se puede evitar. (y con "esto" no me refiero a "especie", me refiero a la operación "distinta" Podría ser doen con ordenación o hash, el método que el optimizador puede y elige a..)
ypercubeᵀᴹ