Question

Je voudrais faire une union de deux tables qui sont en fait dans une constellation hiérarchique.

Comment puis-je écrire que l'algèbre relationnelle? Dis tableau A est le parent de B dans un rapport 1:. N relation

D'abord, je fais une sélection sur A et je veux faire seulement une union avec ces entrées B qui seraient en se joindre à la sélection sur A.

Je voudrais l'écrire la façon dont une base de données serait l'évaluer.

Y at-il une telle chose comme une union conditionnelle?

Était-ce utile?

La solution

Je ne sais pas ce que vous entendez par une UNION. S'il vous plaît expliquer!

Si vous faites référence à l'opérateur UNION qui combine verticalement « jeu de lignes », alors cela pourrait faire l'affaire pour vous:

SELECT
   CASE X.Which WHEN 1 THEN A.Column1 ELSE B.Column1 END Column1,
   CASE X.Which WHEN 1 THEN A.Column2 ELSE B.Column2 END Column2,
   ...
FROM
   TableA A
   CROSS JOIN (
      SELECT 1
      UNION ALL SELECT 2
   ) X (Which)
   LEFT JOIN TableB B
      ON B.AId = A.Id
      AND X.Which = 2
WHERE
  X.Which = 1
  OR B.AId IS NOT NULL

Cela va faire une opération de balayage unique sur les deux tables, plutôt que les au moins deux analyses sur le tableau A pour la requête suivante:

SELECT
   A.Column1,
   A.Column2,
   ...
FROM
   TableA A
UNION ALL
SELECT
   B.Column1,
   B.Column2,
   ...
FROM
   TableA A
   INNER JOIN TableB B
      ON B.AId = A.Id

Maintenant, il est possible quand vous avez dit que vous UNION voulais simplement dire une intersection mathématique, auquel cas la dernière SELECT sera au-dessus de ce que vous avez besoin, simple opération JOIN:

SELECT
   A.Whatever,
   B.Whatever,
   ...
FROM
   TableA A
   INNER JOIN TableB B
      ON B.AId = A.Id

UPDATE

Apparemment, certains moteurs de DB ont des capacités différentes. Par exemple, les deux dernières requêtes dans mon exemple de script ci-dessous (aurait) ont des plans d'exécution très différents dans MySQL, mais ils sont identiques dans SQL Server, qui sélectionne le meilleur chemin d'accès en changeant l'ordre de jointure, la position d'entrée gauche / droite, et le déplacement Les conditions dans le au besoin. Il n'est pas coincé faire JOIN première et seconde oùS.

Pour appuyer ma demande à propos de serveur SQL, je cuisinais jusqu'à un script de test. Cette charge une table parent avec 1 million de lignes et une table enfant avec environ 2,5 millions de lignes. Les lignes individuelles que nous recherchons obtenir mis bien profondément dans la pile (totalement inutile, je sais, mais bon, c'était amusant).

CREATE DATABASE Proof;
GO
ALTER DATABASE Proof SET RECOVERY SIMPLE --no need to bloat the tran log
USE Proof;
GO
CREATE TABLE books (
   id int identity(1,1) NOT NULL CONSTRAINT PK_books PRIMARY KEY CLUSTERED,
   title varchar(100)
);

CREATE TABLE characters (
   book_id int not null constraint fk_characters foreign key references books (id),
   name varchar(100),
   CONSTRAINT PK_characters PRIMARY KEY CLUSTERED (book_id, name)
);

SET NOCOUNT ON;
DECLARE
   @book int,
   @rowcount int,
   @lastbookid int,
   @which int;

SET @book = Coalesce((SELECT Count(*) FROM books), 0);
SET @which = 1;
WHILE 1 = 1 BEGIN
   INSERT books
   SELECT Left(Replicate('-' + Convert(varchar(11), @book + v.number), 20), 100)
   FROM master.dbo.spt_values v
   WHERE   
      v.type = 'P'
      AND v.number < 1000000 - @book;

   SELECT @rowcount = @@rowcount, @lastbookid = scope_identity();
   IF @rowcount = 0 BREAK;
   SET @book = @book + @rowcount;

   INSERT characters
   SELECT
      B.id, Left(Replicate('|' + Convert(varchar(11), v.number), 20), 100)
   FROM
      books B
      CROSS JOIN master.dbo.spt_values v
   WHERE
      B.id BETWEEN @lastbookid - @rowcount + 1 AND @lastbookid
      AND v.type = 'P'
      AND v.number BETWEEN 1 AND Convert(int, Rand() * 4) + 1;


   IF @book >= 250000 AND @which = 1 BEGIN -- put them deep inside
      INSERT books VALUES ('The Frog and the Sorcerer');
      INSERT characters
      SELECT scope_identity(), name
      FROM (
          SELECT 'Frog' UNION ALL SELECT 'Sorcerer'
      ) x (name);
      SET @book = @book + 1;
      SET @which = @which + 1;
   END
   ELSE IF @book >= 500000 AND @which = 2 BEGIN
      INSERT books VALUES ('The Princess and the Pea');
      INSERT characters
      SELECT scope_identity(), name
      FROM (
          SELECT 'Princess' UNION ALL SELECT 'Pea'
      ) x (name);
      SET @book = @book + 1;
      SET @which = @which + 1;
   END
   ELSE IF @book >= 750000 AND @which = 3 BEGIN
      INSERT books VALUES ('Two Ways to Tango');
      INSERT characters
      SELECT scope_identity(), name
      FROM (
          SELECT 'Tango Alpha' UNION ALL SELECT 'Tango Omega'
      ) x (name);
      SET @book = @book + 1;
      SET @which = @which + 1;
   END;
END;
GO
SET SHOWPLAN_ALL ON;
GO
SELECT A.title,B.name
FROM
    books A
    LEFT JOIN characters B
        ON A.id = B.book_id
WHERE
    A.title IN ('Two Ways to Tango', 'The Frog and the Sorcerer')
OPTION (MAXDOP 1);
GO
SET SHOWPLAN_ALL OFF;
GO
SET SHOWPLAN_ALL ON;
GO
SELECT A.title, B.name
FROM
    (
        SELECT id, title FROM books A
        WHERE title IN ('Two Ways to Tango', 'The Frog and the Sorcerer')
    ) A
    LEFT JOIN characters B
        ON A.id = B.book_id
OPTION (MAXDOP 1);
GO
SET SHOWPLAN_ALL OFF;
GO
USE master;
GO
DROP DATABASE Proof;

Les deux plans d'exécution sont identiques. Je retins le parallélisme car il était le bruit inutile (les plans étaient toujours les mêmes). Voici le résultat de la SHOWPLAN avec la requête retirée (la seule partie qui était différente).

StmtText                                                                                                                                                                                                                               StmtId NodeId Parent PhysicalOp           LogicalOp            Argument                                                                                                                                                                                               DefinedValues         EstimateRows EstimateIO EstimateCPU  AvgRowSize TotalSubtreeCost OutputList              Warnings Type     Parallel EstimateExecutions
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ------ ------ ------ -------------------- -------------------- ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ --------------------- ------------ ---------- ------------ ---------- ---------------- ----------------------- -------- -------- -------- ------------------
                                                                                                                                                                                                                                       1      1      0      NULL                 NULL                 1                                                                                                                                                                                                      NULL                  2.994377     NULL       NULL         NULL       12.71991         NULL                    NULL     SELECT   0        1
  |--Nested Loops(Left Outer Join, OUTER REFERENCES:([A].[id]))                                                                                                                                                                        1      2      1      Nested Loops         Left Outer Join      OUTER REFERENCES:([A].[id])                                                                                                                                                                            NULL                  2.994377     0          0.0000125165 151        12.71991         [A].[title], [B].[name] NULL     PLAN_ROW 0        1
       |--Clustered Index Scan(OBJECT:([Proof].[dbo].[books].[PK_books] AS [A]), WHERE:([Proof].[dbo].[books].[title] as [A].[title]='The Frog and the Sorcerer' OR [Proof].[dbo].[books].[title] as [A].[title]='Two Ways to Tango')) 1      3      2      Clustered Index Scan Clustered Index Scan OBJECT:([Proof].[dbo].[books].[PK_books] AS [A]), WHERE:([Proof].[dbo].[books].[title] as [A].[title]='The Frog and the Sorcerer' OR [Proof].[dbo].[books].[title] as [A].[title]='Two Ways to Tango') [A].[id], [A].[title] 1            10.73646   1.100157     114        11.83662         [A].[id], [A].[title]   NULL     PLAN_ROW 0        1
       |--Clustered Index Seek(OBJECT:([Proof].[dbo].[characters].[PK_characters] AS [B]), SEEK:([B].[book_id]=[Proof].[dbo].[books].[id] as [A].[id]) ORDERED FORWARD)                                                                1      4      2      Clustered Index Seek Clustered Index Seek OBJECT:([Proof].[dbo].[characters].[PK_characters] AS [B]), SEEK:([B].[book_id]=[Proof].[dbo].[books].[id] as [A].[id]) ORDERED FORWARD                                                                [B].[name]            2.994377     0.003125   0.0001602938 50         0.003285294      [B].[name]              NULL     PLAN_ROW 0        0

Autres conseils

Si je comprends bien la question, votre tâche peut être résolu en utilisant des requêtes récursives. Oracle (voir et SQLServer (2005 et plus) à la fois soutenir. Certes, différents fournisseurs de SGTP utilisent une syntaxe légèrement différente.

Vous Intersection moyen? Tenez compte relvars Customers et Orders avec une correspondance où un client a zéro, un ou plusieurs ordres (je ne parlerais à cela comme une hiérarchie, cependant). Pour trouver des clients qui ont des commandes:

( Customers { customer_ID } ) INTERSECT ( Orders { customer_ID } ) 

Je soupçonne plutôt ce n'est pas ce que vous entendez, dans lequel il vous plaît modifier votre question d'ajouter par exemple les données et les résultats attendus.

Licencié sous: CC-BY-SA avec attribution
Non affilié à dba.stackexchange
scroll top