in

UGISS Community

Il sito della community dello User Group Italiano di SQL Server

select, not in, chiavi composite...

Last post 11-02-2007 22.30 by lbenaglia. 5 replies.
Page 1 of 1 (6 items)
Sort Posts: Previous Next
  • 10-30-2007 9.54

    select, not in, chiavi composite...

    Ciao a tutti...

    Se abbiamo due tabelle con chiavi composite:

    CREATE TABLE [dbo].[tbl1](
     [c1] [int] IDENTITY(1,1) NOT NULL,
     [c2] [int] NOT NULL,
     [c3] [int] NOT NULL,
     [datains] [datetime] NULL DEFAULT (getdate()),
     CONSTRAINT [PK_tbl1] PRIMARY KEY CLUSTERED
    (
     [c2] ASC,
     [c3] ASC
    )WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
    ) ON [PRIMARY]

    CREATE TABLE [dbo].[tbl2](
     [c1] [int] IDENTITY(1,1) NOT NULL,
     [c2] [int] NOT NULL,
     [c3] [int] NOT NULL,
     [datains] [datetime] NULL DEFAULT (getdate()),
     CONSTRAINT [PK_tbl2] PRIMARY KEY CLUSTERED
    (
     [c2] ASC,
     [c3] ASC
    )WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
    ) ON [PRIMARY]

    popolate con dati tipo:

    insert into tbl1 (c2, c3) values (1, 1)
    insert into tbl1 (c2, c3) values (1, 2)
    insert into tbl1 (c2, c3) values (1, 3)
    insert into tbl1 (c2, c3) values (1, 4)
    insert into tbl1 (c2, c3) values (1, 5)
    insert into tbl1 (c2, c3) values (2, 1)
    insert into tbl1 (c2, c3) values (3, 1)
    insert into tbl1 (c2, c3) values (3, 2)
    insert into tbl1 (c2, c3) values (4, 1)
    insert into tbl1 (c2, c3) values (5, 1)

    insert into tbl2 (c2, c3) values (1, 6)
    insert into tbl2 (c2, c3) values (1, 1)
    insert into tbl2 (c2, c3) values (1, 5)
    insert into tbl2 (c2, c3) values (2, 1)
    insert into tbl2 (c2, c3) values (2, 2)
    insert into tbl2 (c2, c3) values (3, 2)
    insert into tbl2 (c2, c3) values (4, 3)
    insert into tbl2 (c2, c3) values (4, 4)
    insert into tbl2 (c2, c3) values (4, 5)
    insert into tbl2 (c2, c3) values (5, 1)
    insert into tbl2 (c2, c3) values (7, 1)
    insert into tbl2 (c2, c3) values (3, 3)

    A PARITA' DI CHIAVE PRIMARIA... come troviamo tutte le righe della tabella tbl1 che non sono presenti nella tabella tbl2?
    Io lo risolvo cosi'...

    select * from tbl1
    where cast(c2 as varchar(4)) +'-'+ cast(c3 as varchar(4))
    not in (select cast(c2 as varchar(4)) +'-'+ cast(c3 as varchar(4)) from tbl2)

    ma ho il dubbio che non sia proprio la via migliore....
    Soprattutto perche' devo andare a castare tutto, compresi i numerici...

    Dove e' che sbaglio?

    Ciao
    Ale

    • Post Points: 35
  • 10-31-2007 15.40 In reply to

    • s.greci
    • Top 25 Contributor
      Male
    • Joined on 05-16-2007
    • Alba (CN)
    • Posts 101
    • Points 1.020

    Re: select, not in, chiavi composite...

    Ciao Ale,

    io utilizzerei al posto della IN uno statement di LEFT JOIN: 

    SELECT t1.*
    FROM tbl1 t1
    LEFT JOIN tbl2 t2
        ON t1.c2 = t2.c2
        AND t1.c3 = t2.c3
    WHERE
        t2.c2 IS NULL

    Ciao :-)

    Simone
     

    Simone Greci
    SQL Server MCP, MCTS
    http://community.ugiss.org/blogs/s.greci/
    BI Specialist @ Solid Quality Learning Italy
    • Post Points: 20
  • 11-01-2007 20.09 In reply to

    • dmauri
    • Top 10 Contributor
      Male
    • Joined on 05-14-2007
    • Novate Milanese
    • Posts 1.179
    • Points 15.440

    Re: select, not in, chiavi composite...

    Esatto. Un'altra soluzione è anche l'utilizzo della clausola NOT EXISTS:

    select
        t1.*
    from
        [dbo].[tbl1] as t1
    where not exists(select * from [dbo].[tbl2] as t2 where t2.[c2] = t1.[c2] and t2.[c3] = t1.[c3])

     

    Davide Mauri
    Microsoft MVP - SQL Server, MCP, MCAD, MCDBA, MCT - http://www.davidemauri.it
    Socio Fondatore e Mentor di Solid Quality Learning Italy - http://www.solidq.com
    Presidente di UGISS: User Group Italiano Sql Server - http://www.ugiss.org
    • Post Points: 5
  • 11-02-2007 16.50 In reply to

    • lbenaglia
    • Top 25 Contributor
      Male
    • Joined on 05-15-2007
    • Vimercate (Milano)
    • Posts 88
    • Points 1.335

    Re: select, not in, chiavi composite...

    Ciao Ale,

    Se utilizzi SQL Server 2005 puoi sfruttare due novità introdotte con questa edizione:

    • L'operatore EXCEPT
    • Le common table expression (CTE).

    L'operatore EXCEPT restituisce i valori distinti dalla query di sinistra che non sono presenti nella query di destra.
    Una CTE ti permette di definire una query temporanea il cui scope è relativo ad un singolo comando di SELECT, INSERT, UPDATE, o DELETE.

    Nell'esempio che vado a proporti ho utilizzato l'operatore EXCEPT per ottenere l'elenco dei valori relativi alle primary keys della prima tabella non presenti nella seconda, ed una CTE per scrivere elegantemente l'intero comando: Cool

    WITH CTE_GetKey AS
    (
        
    SELECT c2c3
        
    FROM dbo.tbl1

        
    EXCEPT

        SELECT 
    c2c3
        
    FROM dbo.tbl2
    )
    SELECT t1.*
    FROM dbo.tbl1 AS t1
    JOIN CTE_GetKey AS cte
    ON t1.c2 cte.c2
    AND t1.c3 cte.c3;

    Per ulteriori dettagli consulta i seguenti paragrafi sui Books Online:

     Ciao!

    Lorenzo Benaglia
    Microsoft MVP - SQL Server
    http://blogs.dotnethell.it/lorenzo
    http://italy.mvps.org
    Filed under: ,
    • Post Points: 20
  • 11-02-2007 22.15 In reply to

    Re: select, not in, chiavi composite...

    Ciao Lore'....

    grazie per l'EXCEPT... le CTE non posso usarle in una SP, quindi le levo....

    adesso ho 4 possibili vie....

    lunedi le metto in pratica tutte e vi dico chi ha il metodo migliore....

    vi posto piani e statistiche....

    Buon WE....
    Ale

    • Post Points: 20
  • 11-02-2007 22.30 In reply to

    • lbenaglia
    • Top 25 Contributor
      Male
    • Joined on 05-15-2007
    • Vimercate (Milano)
    • Posts 88
    • Points 1.335

    Re: select, not in, chiavi composite...

    > grazie per l'EXCEPT... le CTE non posso usarle in una SP, quindi le levo....

    Ciao Ale,

    Chi ti ha detto che le CTE non puoi usarle nel body di una stored procedure? Big Smile

    Osserva il seguente esempio (questa volta completo):

    USE tempdb;

    CREATE TABLE dbo.tbl1(
    c1 int IDENTITY(1,1) NOT NULL,
    c2 int NOT NULL,
    c3 int NOT NULL,
    datains datetime NULL DEFAULT (getdate()),
    CONSTRAINT PK_tbl1 PRIMARY KEY CLUSTERED (c2, c3)
    );

    CREATE TABLE dbo.tbl2(
    c1 int IDENTITY(1,1) NOT NULL,
    c2 int NOT NULL,
    c3 int NOT NULL,
    datains datetime NULL DEFAULT (getdate()),
    CONSTRAINT PK_tbl2 PRIMARY KEY CLUSTERED (c2, c3)
    );

    INSERT INTO dbo.tbl1 (c2, c3) VALUES (1, 1);
    INSERT INTO dbo.tbl1 (c2, c3) VALUES (1, 2);
    INSERT INTO dbo.tbl1 (c2, c3) VALUES (1, 3);
    INSERT INTO dbo.tbl1 (c2, c3) VALUES (1, 4);
    INSERT INTO dbo.tbl1 (c2, c3) VALUES (1, 5);
    INSERT INTO dbo.tbl1 (c2, c3) VALUES (2, 1);
    INSERT INTO dbo.tbl1 (c2, c3) VALUES (3, 1);
    INSERT INTO dbo.tbl1 (c2, c3) VALUES (3, 2);
    INSERT INTO dbo.tbl1 (c2, c3) VALUES (4, 1);
    INSERT INTO dbo.tbl1 (c2, c3) VALUES (5, 1);

    INSERT INTO dbo.tbl2 (c2, c3) VALUES (1, 6);
    INSERT INTO dbo.tbl2 (c2, c3) VALUES (1, 1);
    INSERT INTO dbo.tbl2 (c2, c3) VALUES (1, 5);
    INSERT INTO dbo.tbl2 (c2, c3) VALUES (2, 1);
    INSERT INTO dbo.tbl2 (c2, c3) VALUES (2, 2);
    INSERT INTO dbo.tbl2 (c2, c3) VALUES (3, 2);
    INSERT INTO dbo.tbl2 (c2, c3) VALUES (4, 3);
    INSERT INTO dbo.tbl2 (c2, c3) VALUES (4, 4);
    INSERT INTO dbo.tbl2 (c2, c3) VALUES (4, 5);
    INSERT INTO dbo.tbl2 (c2, c3) VALUES (5, 1);
    INSERT INTO dbo.tbl2 (c2, c3) VALUES (7, 1);
    INSERT INTO dbo.tbl2 (c2, c3) VALUES (3, 3);
    GO

    CREATE PROCEDURE dbo.up_GetRows
    AS
    WITH CTE_GetKey AS
    (
        SELECT c2, c3
        FROM dbo.tbl1

        EXCEPT

        SELECT c2, c3
        FROM dbo.tbl2
    )
    SELECT t1.*
    FROM dbo.tbl1 AS t1
    JOIN CTE_GetKey AS cte
    ON t1.c2 = cte.c2
    AND t1.c3 = cte.c3;
    GO

    EXEC dbo.up_GetRows;

    /* Output:

    c1          c2          c3          datains
    ----------- ----------- ----------- -----------------------
    2           1           2           2007-11-02 22:25:15.037
    3           1           3           2007-11-02 22:25:15.037
    4           1           4           2007-11-02 22:25:15.037
    7           3           1           2007-11-02 22:25:15.037
    9           4           1           2007-11-02 22:25:15.037

    (5 row(s) affected)

    */

    DROP PROCEDURE dbo.up_GetRows;
    DROP TABLE dbo.tbl1, dbo.tbl2;

    Come puoi vedere le CTE possono tranquillamente essere utilizzate in una stored procedure.

    > lunedi le metto in pratica tutte e vi dico chi ha il metodo migliore....

    Probabilmente i metodi proposti da Simone e Davide risulteranno essere più efficienti rispetto alla soluzione proposta, io volevo limitarmi ad esplorare una nuova strada utilizzando un paio di novità introdotte con SQL Server 2005 Smile

    La cosa affascinante dei DBMS è la possibilità di ottenere il medesimo risultato applicando logiche del tutto diverse.

    Ciao!

    Lorenzo Benaglia
    Microsoft MVP - SQL Server
    http://blogs.dotnethell.it/lorenzo
    http://italy.mvps.org
    Filed under: , ,
    • Post Points: 5
Page 1 of 1 (6 items)
(C) 2007 User Group Italiano di SQL Server