Oprettet fre. d. 23. november 2007 kl. 12:31:28

donkazz
donkazz (11.670 point. Point ude: 1.395)

SELECT WHERE IN performance er dårligt? Alternativer?

Hej alle!

Jeg har en virkeligt lang og kringlet SQL, som jeg udelukkende fik til at virke ved at bruge en forfærdeligt masse WHERE IN sætninger. Jeg læste i et tidligere spørgsmål, at brugen af WHERE IN var skidt for performance i forhold til at den laver en lykke for hver WHERE IN (SELECT...) i hver række den looper igennem. Se den logik kan jeg godt følge, men har jeg et alternativ? Hvad kan jeg gøre for optimal performance men med samme resultat som SELECT FROM WHERE IN (SELECT...) ?

Skrevet fre. d. 23. november 2007 kl. 12:46:33| #1

sherlock
sherlock (30.279 point)
Det er jo svært, når man ikke kender din database og sql'en.

Du kan måske lave unions af nogle mere simple selects ?

Hvis dine subselects returnerer små datasets fra en stor tabel, er det en mulighed at lave temporære tabeller , så der kun er 1 select mod hele den store tabel og subselects mod den lille.

Skrevet fre. d. 23. november 2007 kl. 12:49:18| #2

janus_007
janus_007 (30.915 point)
Ja where in sucks... Og der bør være andre måder at løse opgaven på *GG*

Post din SQL her, det vil gøre det nemmere for os at komme med forslag.

Skrevet fre. d. 23. november 2007 kl. 13:44:12| #3

donkazz
donkazz (11.670 point)
Se om I kan gennemskue den... ellers kan I få en forklaring (den bliver lang!) :-D

WITH prodCatsCTE(prodCatId, prodCatName, prodCatBelongsTo, prodCatOrderNr, depth, sortcol) 
    AS 
    ( 
    SELECT pcs.prodCatId, pcs.prodCatName, pcs.prodCatBelongsTo, pcs.prodCatOrderNr, 0, CAST(pcs.prodCatId AS VARBINARY(900)) 
    FROM prodCats pcs 
    WHERE 
        pcs.prodCatBelongsTo = 0 
    AND 
        prodCatId IN 
        (SELECT prodCatBelongsTo FROM prodCats WHERE prodCatId IN 
            (SELECT prodCatId FROM products WHERE supplierId IN 
                (SELECT supplierId FROM sup_cust_conn WHERE customerId = 5) 
            ) 
        )     
    UNION ALL 
    SELECT p.prodCatId, p.prodCatName, p.prodCatBelongsTo, p.prodCatOrderNr, pc.depth+1, 
    CAST(sortcol + CAST(p.prodCatOrderNr AS BINARY(4)) AS VARBINARY(900)) 
    FROM prodCats p 
    JOIN prodCatsCTE AS pc 
    ON p.prodCatBelongsTo = pc.prodCatId 
    WHERE pc.prodCatId = p.prodCatBelongsTo 
    AND p.prodCatId IN 
            (SELECT pro.prodCatId FROM products pro INNER JOIN prodCats pp ON pro.prodCatId=pp.prodCatId WHERE pro.supplierId IN 
                (SELECT supplierId FROM sup_cust_conn WHERE customerId = 5) 
            AND pp.prodCatBelongsTo = pc.prodCatId) 
    AND 
    pc.prodCatId = 1 
    OR 
    (pc.prodCatId = (SELECT prodCatBelongsTo FROM prodCats WHERE prodCatId = 1 )     
    AND p.prodCatId IN 
            (SELECT pro.prodCatId FROM products pro INNER JOIN prodCats pp ON pro.prodCatId=pp.prodCatId WHERE pro.supplierId IN 
                (SELECT supplierId FROM sup_cust_conn WHERE customerId = 5) 
            AND pp.prodCatBelongsTo = pc.prodCatId))     
    )     
    SELECT 
    REPLICATE('    ', depth) + prodCatName AS prodCatName, prodCatId, prodCatBelongsTo, prodCatOrderNr, depth 
    FROM prodCatsCTE 
    ORDER BY sortcol

Skrevet fre. d. 23. november 2007 kl. 14:10:44| #4

dr_chaos
dr_chaos (73.666 point)
SKriv dine where in om til joins i stedet for.
eksempel :
pro.supplierId IN
                (SELECT supplierId FROM sup_cust_conn WHERE customerId = 5) 

til
JOIN  sup_cust_conn s ON  s.supplierId =  pro.supplierId AND s.customerId =5


en not in kan laves med en

LEFT JOIN  sup_cust_conn s ON  s.supplierId =  pro.supplierId AND s.customerId =5
WHERE s.supplierId IS NOT NULL

Skrevet fre. d. 23. november 2007 kl. 14:27:47| #5

donkazz
donkazz (11.670 point)
Så prøvede jeg at joine istedet...

WITH prodCatsCTE(prodCatId, prodCatName, prodCatBelongsTo, prodCatOrderNr, depth, sortcol) 
    AS 
    ( 
    SELECT pcs.prodCatId, pcs.prodCatName, pcs.prodCatBelongsTo, pcs.prodCatOrderNr, 0, CAST(pcs.prodCatId AS VARBINARY(900)) 
    FROM prodCats pcs
        JOIN prodCats p1 ON pcs.prodCatId=p1.prodCatBelongsTo
            JOIN products p2 ON pcs.prodCatId=p2.prodCatId
                JOIN sup_cust_conn s ON p2.supplierId=s.supplierId
    WHERE s.customerId = 5 AND pcs.prodCatBelongsTo = 0 
    UNION ALL 
    SELECT p.prodCatId, p.prodCatName, p.prodCatBelongsTo, p.prodCatOrderNr, pc.depth+1, 
    CAST(sortcol + CAST(p.prodCatOrderNr AS BINARY(4)) AS VARBINARY(900)) 
    FROM prodCats p 
    JOIN prodCatsCTE AS pc 
    ON p.prodCatBelongsTo = pc.prodCatId 
    )     
    SELECT 
    REPLICATE('    ', depth) + prodCatName AS prodCatName, prodCatId, prodCatBelongsTo, prodCatOrderNr, depth 
    FROM prodCatsCTE 
    ORDER BY sortcol

Nu eksekverer den uden problemer, dog er der ingen resultater, hvor der før var følgende:

prodCatName | prodCatId, prodCatBelongsTo, prodCatOrderNr, depth
Skuret    1    0    10    0
    Hammere    4    1    10    1
    Save    5    1    20    1
    River    6    1    30    1
Taget    3    0    30    0

Skrevet fre. d. 23. november 2007 kl. 18:26:06| #6

janus_007
janus_007 (30.915 point)
Der har sikkert sneget sig et par fejl ind.

Jeg kunne godt tænke mig du fjernede din union her under debug-fasen. Den kan vi altid få til at virke senere :)

Kan du forsøge med:

WITH prodCatsCTE(prodCatId, prodCatName, prodCatBelongsTo, prodCatOrderNr, depth, sortcol) 
    AS 
    ( 
    SELECT pcs.prodCatId, pcs.prodCatName, pcs.prodCatBelongsTo, pcs.prodCatOrderNr, 0, CAST(pcs.prodCatId AS VARBINARY(900)) 
    FROM prodCats pcs
        inner join prodCats p1
      ON pcs.prodCatId=p1.prodCatBelongsTo
        inner join products p2
      ON pcs.prodCatId=p2.prodCatId
        inner join sup_cust_conn s
      ON p2.supplierId=s.supplierId
    WHERE s.customerId = 5
    AND pcs.prodCatBelongsTo = 0  )


Er der null values i nogle af de felter du joiner op imod? Det må der nemlig ikke være! Så skal du bruge en isnull(p1.prodCatBelongsTo, somethingjadajada) *S*

Vi skal nok få løst det :)

Skrevet man. d. 26. november 2007 kl. 09:40:19| #7

donkazz
donkazz (11.670 point)
Uhm stadig ingen resultater... Der kan sagtens være null værdier i nogle af rækkerne, for ideen er jo at den kun hiver de relevante resultater ud som ikke er null, men jeg prøvede at sætte "AND IsNull(pcs.prodCatBelongsTo, 0)", men det er jeg ret sikker på er forkert, da jeg ikke er 100% nede med det der IsNull halløj.... :-D

Hvad skal jeg gøre?

Skrevet man. d. 26. november 2007 kl. 13:45:40| #8

janus_007
janus_007 (30.915 point)
hey donkazz...

Ja det er også ok at den kun hiver ud hver der ikke er null, det løses vha. sql-udtrykket.

Jeg vil gerne være helt sikker.. Forsøgte du uden en union? Og så må vi igang med at debugge :-) dvs. tag det her udtryk:

SELECT pcs.prodCatId, pcs.prodCatName, pcs.prodCatBelongsTo, pcs.prodCatOrderNr, 0, CAST(pcs.prodCatId AS VARBINARY(900)) 
    FROM prodCats pcs
        inner join prodCats p1
      ON pcs.prodCatId=p1.prodCatBelongsTo
        inner join products p2
      ON pcs.prodCatId=p2.prodCatId
        inner join sup_cust_conn s
      ON p2.supplierId=s.supplierId
    WHERE s.customerId = 5
    AND pcs.prodCatBelongsTo = 0

og skriv om til:
SELECT pcs.prodCatId, pcs.prodCatName, pcs.prodCatBelongsTo, pcs.prodCatOrderNr, 0, CAST(pcs.prodCatId AS VARBINARY(900)) 
    FROM prodCats pcs
        inner join prodCats p1
      ON pcs.prodCatId=p1.prodCatBelongsTo
--        inner join products p2
--      ON pcs.prodCatId=p2.prodCatId
--        inner join sup_cust_conn s
--      ON p2.supplierId=s.supplierId
    WHERE  pcs.prodCatBelongsTo = 0

Så ser vi lige ad om der overhovedet er noget data der matcher prodcatid = ..belongsto

Hvis der så er, så udfør næste skridt her:
SELECT pcs.prodCatId, pcs.prodCatName, pcs.prodCatBelongsTo, pcs.prodCatOrderNr, 0, CAST(pcs.prodCatId AS VARBINARY(900)) 
    FROM prodCats pcs
        inner join prodCats p1
      ON pcs.prodCatId=p1.prodCatBelongsTo
        inner join products p2
      ON pcs.prodCatId=p2.prodCatId
--        inner join sup_cust_conn s
--      ON p2.supplierId=s.supplierId
    WHERE  pcs.prodCatBelongsTo = 0

Altså test for match imellem prodCatId. Jeg kunne godt tænke mig at se hvor katten det er den fejler?

Ellers må du give lidt data og tabelstruktur så jeg bedre kan se hvad vi taler om hehe....

PS: Du skriver "den kun hiver de relevante resultater ud som ikke er null", kan du evt. gøre sådan her:
ON isnull(p2.supplierId,-1) = isnull(s.supplierId, -2)

Skrevet tir. d. 27. november 2007 kl. 13:03:48| #9

donkazz
donkazz (11.670 point)
Så kom vi lidt videre... :-D

Følgende:
WITH prodCatsCTE(prodCatId, prodCatName, prodCatBelongsTo, prodCatOrderNr, depth, sortcol) 
    AS 
    ( 
SELECT pcs.prodCatId, pcs.prodCatName, pcs.prodCatBelongsTo, pcs.prodCatOrderNr, 0, CAST(pcs.prodCatId AS VARBINARY(900)) 
    FROM prodCats pcs
        inner join prodCats p1
      ON pcs.prodCatId=p1.prodCatBelongsTo
--        inner join products p2
--      ON pcs.prodCatId=p2.prodCatId
--        inner join sup_cust_conn s
--      ON p2.supplierId=s.supplierId
    WHERE  pcs.prodCatBelongsTo = 0 )   
    SELECT 
    REPLICATE('    ', depth) + prodCatName AS prodCatName, prodCatId, prodCatBelongsTo, prodCatOrderNr, depth 
    FROM prodCatsCTE 
    ORDER BY sortcol

Gav

(prodCatName, prodCatId, prodCatBelongsTo, prodCatOrderNr, depth)
Badeværelset    1    0    10    0
Badeværelset    1    0    10    0
Badeværelset    1    0    10    0
Varmesystemer    3    0    30    0
Varmesystemer    3    0    30    0
Varmesystemer    3    0    30    0

Hvor imod:

WITH prodCatsCTE(prodCatId, prodCatName, prodCatBelongsTo, prodCatOrderNr, depth, sortcol) 
    AS 
    ( 
SELECT pcs.prodCatId, pcs.prodCatName, pcs.prodCatBelongsTo, pcs.prodCatOrderNr, 0, CAST(pcs.prodCatId AS VARBINARY(900)) 
    FROM prodCats pcs
        inner join prodCats p1
      ON pcs.prodCatId=p1.prodCatBelongsTo
        inner join products p2
      ON pcs.prodCatId=p2.prodCatId
--        inner join sup_cust_conn s
--      ON p2.supplierId=s.supplierId
    WHERE  pcs.prodCatBelongsTo = 0 )   
    SELECT 
    REPLICATE('    ', depth) + prodCatName AS prodCatName, prodCatId, prodCatBelongsTo, prodCatOrderNr, depth 
    FROM prodCatsCTE 
    ORDER BY sortcol

Gav ingen resultater.. :-o

Giver det mening?

Skrevet tor. d. 29. november 2007 kl. 00:11:59| #10

janus_007
janus_007 (30.915 point)
hey.. beklager min sene kommentar.

hmm, er du sikker på at prodCats.prodCatId = 0 også findes i tabellen products.prodCatId ?

Skrevet tor. d. 29. november 2007 kl. 08:18:10| #11

donkazz
donkazz (11.670 point)
Altså hvis prodCats.prodCatId = 0, så eksisterer produktkategorien ikke. Hvis prodCats.prodCatBelongsTo = 0, så er produktkategorien top level.
products.prodCatId vil altid være forskellig fra 0, for hvis en produktkategori bliver slettet, så skal produkterne alligevel ikke vises.

Skrevet tor. d. 29. november 2007 kl. 08:35:05| #12

donkazz
donkazz (11.670 point)
Nu prøvede jeg lige med:

WITH prodCatsCTE(prodCatId, prodCatName, prodCatBelongsTo, prodCatOrderNr, depth, sortcol) 
    AS 
    ( 
SELECT pcs.prodCatId, pcs.prodCatName, pcs.prodCatBelongsTo, pcs.prodCatOrderNr, 0, CAST(pcs.prodCatId AS VARBINARY(900)) 
    FROM prodCats pcs
        inner join prodCats p1
      ON pcs.prodCatId=p1.prodCatBelongsTo
        inner join products p2
      ON p1.prodCatId=p2.prodCatId
--        inner join sup_cust_conn s
--      ON p2.supplierId=s.supplierId
    WHERE  pcs.prodCatBelongsTo = 0 )   
    SELECT 
    REPLICATE('    ', depth) + prodCatName AS prodCatName, prodCatId, prodCatBelongsTo, prodCatOrderNr, depth 
    FROM prodCatsCTE 
    ORDER BY sortcol


Hvor jeg laver en inner join på p1.prodCatId=p2.prodCatId i stedet for pcs.prodCatId=p2.prodCatId, hvilket også giver mere mening, da p1 er den prodCat som products tilhører, hvor pcs er den prodCat som p1 tilhører. Dvs. produkter aldrig tilhører top level prodCats.

Til gengæld får jeg hver top level prodCat samme antal gange som det antal produkter der i sidste ende ligger under. :(
Badeværelset    1    0    10    0
Badeværelset    1    0    10    0
Badeværelset    1    0    10    0
Badeværelset    1    0    10    0
Badeværelset    1    0    10    0
Badeværelset    1    0    10    0
Badeværelset    1    0    10    0
Badeværelset    1    0    10    0
Badeværelset    1    0    10    0
Varmesystemer    3    0    30    0

Skrevet fre. d. 30. november 2007 kl. 00:06:03| #13

janus_007
janus_007 (30.915 point)
ahh nu er det måske ved at dæmre *GG*

Jeg tror vi har lavet en join fejl fra starten af.

WITH prodCatsCTE(prodCatId, prodCatName, prodCatBelongsTo, prodCatOrderNr, depth, sortcol) 
    AS 
    ( 
SELECT pcs.prodCatId, pcs.prodCatName, pcs.prodCatBelongsTo, pcs.prodCatOrderNr, 0, CAST(pcs.prodCatId AS VARBINARY(900)) 
    FROM prodCats pcs
inner join (SELECT prodCatBelongsTo FROM prodCats p1_inner
        inner join products p2
            on p2.prodCatId = p1_inner.prodCatId
        inner join sup_cust_conn s
            on s.supplierId = p2.supplierId
                where s.customerId = 5) as p
on p.prodCatBelongsTo = pcs.prodCatId
)
SELECT 
    REPLICATE('    ', depth) + prodCatName AS prodCatName, prodCatId, prodCatBelongsTo, prodCatOrderNr, depth 
    FROM prodCatsCTE 
    ORDER BY sortcol



Nu føler jeg mere at joinet er det samme som alle de where-in's :)
Det hele kom sig af at vi tidligt i joinet begrænsede det ved kun at tillade prodCatBelongsTo = 0 og det er jo ikke tilfældet at vi ønsker den begrænsning når vi gerne vil kunne benytte den som sub join.

Well.. prøv lige det der så. pyhaaa tager sørme tid ;-)

Skrevet fre. d. 30. november 2007 kl. 08:32:18| #14

donkazz
donkazz (11.670 point)
Tillad mig at citere dig:
"Vi skal nok få løst det :)"

;-))

Men du har ret, det tager sin tid! :-D Det er også ubetinget den længste SQL jeg nogensinde har rodet med og det må siges at være jomfrurejsen fra de standard SELECT FROM WHERE sætninger jeg hidtil har rodet med. :))

Nå anyways, ovenstående giver:
Badeværelset    1    0    10    0
Badeværelset    1    0    10    0
Badeværelset    1    0    10    0
Badeværelset    1    0    10    0
Badeværelset    1    0    10    0
Varmesystemer    3    0    30    0

Skrevet fre. d. 30. november 2007 kl. 23:00:58| #15

janus_007
janus_007 (30.915 point)
Altså man kunne jo være flabet at lave en distinct
WITH prodCatsCTE(prodCatId, prodCatName, prodCatBelongsTo, prodCatOrderNr, depth, sortcol) 
    AS 
    ( 
SELECT pcs.prodCatId, pcs.prodCatName, pcs.prodCatBelongsTo, pcs.prodCatOrderNr, 0, CAST(pcs.prodCatId AS VARBINARY(900)) 
    FROM prodCats pcs
inner join (SELECT prodCatBelongsTo FROM prodCats p1_inner
        inner join products p2
            on p2.prodCatId = p1_inner.prodCatId
        inner join sup_cust_conn s
            on s.supplierId = p2.supplierId
                where s.customerId = 5) as p
on p.prodCatBelongsTo = pcs.prodCatId
)
SELECT DISTINCT
    REPLICATE('    ', depth) + prodCatName AS prodCatName, prodCatId, prodCatBelongsTo, prodCatOrderNr, depth 
    FROM prodCatsCTE 
    ORDER BY sortcol

Men det er ikke den fedeste løsning, årsagen til at joinet giver så mange badeværelser er fordi der er en eller flere kolonner der ikke joines på.

Prøv at udføre denne her:
SELECT *
    FROM prodCats pcs
inner join (SELECT prodCatBelongsTo FROM prodCats p1_inner
        inner join products p2
            on p2.prodCatId = p1_inner.prodCatId
        inner join sup_cust_conn s
            on s.supplierId = p2.supplierId
                where s.customerId = 5) as p
on p.prodCatBelongsTo = pcs.prodCatId

Og poste det, her burde vi meget gerne kunne se hvilke unikke rækker der eksisterer og så må vi se om vi kan eliminere dem :)

Skrevet man. d. 03. december 2007 kl. 08:50:46| #16

donkazz
donkazz (11.670 point)
Nå nu hiv den også produktbeskrivelsen med ud, så jeg kunne sgu ik lige copy paste det ind til dig.

Kan du se det her?
http://imageshack.dk/ (...)

Skrevet tir. d. 04. december 2007 kl. 10:12:36| #17

janus_007
janus_007 (30.915 point)
Hej..
Jo jeg kan godt se det :) Ja tanken er jo at debugge join og når der opstår dubletter kan man lave en * og der skulle man meget gerne kunne se forskelligheder i hver række hehe... men jeg kan ikke lige se dem her, må jeg sige hmm...

Okay, kunne jeg få dig til at lave en SELECT *
    FROM prodCats pcs
inner join (SELECT prodCatBelongsTo FROM prodCats p1_inner
        inner join products p2
            on p2.prodCatId = p1_inner.prodCatId
        inner join sup_cust_conn s
            on s.supplierId = p2.supplierId
                where s.customerId = 5) as p
on p.prodCatBelongsTo = pcs.prodCatId

Og så se om den kommer med samme resultat?

Hvad giver denne her?:
SELECT prodCatBelongsTo FROM prodCats p1_inner
        inner join products p2
            on p2.prodCatId = p1_inner.prodCatId
        inner join sup_cust_conn s
            on s.supplierId = p2.supplierId
                where s.customerId = 5

Hvis du vil må du gerne poste scriptet til at lave de 3 tabeller med.. så kan jeg selv fylde noget data ind og forsøge med :)

Skrevet tir. d. 04. december 2007 kl. 12:37:44| #18

donkazz
donkazz (11.670 point)
Den første gav samme resultater, den anden gav bare nogle cifre, men samme smøre i virkeligheden.

prodCats:
USE [localTest]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
SET ANSI_PADDING ON
GO
CREATE TABLE [dbo].[prodCats](
    [prodCatId] [int] IDENTITY(1,1) NOT NULL,
    [prodCatName] [varchar](50) NULL,
    [prodCatContent] [varchar](max) NULL,
    [prodCatBelongsTo] [int] NULL,
    [prodCatOrderNr] [int] NULL,
    [disabled] [bit] NULL CONSTRAINT [DF_prodCats_disabled]  DEFAULT ((0)),
CONSTRAINT [PK_prodCats] PRIMARY KEY CLUSTERED
(
    [prodCatId] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
SET ANSI_PADDING OFF

products:
USE [localTest]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
SET ANSI_PADDING ON
GO
CREATE TABLE [dbo].[products](
    [productId] [int] IDENTITY(1,1) NOT NULL,
    [productName] [varchar](50) NULL,
    [shortText] [varchar](200) NULL,
    [orderNr] [int] NULL,
    [prodCatId] [int] NULL,
    [supplierId] [int] NULL,
    [disabled] [bit] NULL CONSTRAINT [DF_products_disabled]  DEFAULT ((0))
CONSTRAINT [PK_products] PRIMARY KEY CLUSTERED
(
    [productId] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
SET ANSI_PADDING OFF

suppliers:
USE [localTest]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
SET ANSI_PADDING ON
GO
CREATE TABLE [dbo].[suppliers](
    [supplierId] [int] IDENTITY(1,1) NOT NULL,
    [supplierName] [varchar](50) NULL,
    [disabled] [bit] NULL CONSTRAINT [DF_suppliers_disabled]  DEFAULT ((0)),
CONSTRAINT [PK_suppliers] PRIMARY KEY CLUSTERED
(
    [supplierId] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
SET ANSI_PADDING OFF

sup_cust_conn:
USE [localTest]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[sup_cust_conn](
    [supCustConnId] [int] IDENTITY(1,1) NOT NULL,
    [supplierId] [int] NULL,
    [customerId] [int] NULL,
CONSTRAINT [PK_sup_cust_conn] PRIMARY KEY CLUSTERED
(
    [supCustConnId] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

GO
ALTER TABLE [dbo].[sup_cust_conn]  WITH CHECK ADD  CONSTRAINT [FK_sup_cust_conn_customers] FOREIGN KEY([customerId])
REFERENCES [dbo].[customers] ([customerId])
GO
ALTER TABLE [dbo].[sup_cust_conn] CHECK CONSTRAINT [FK_sup_cust_conn_customers]
GO
ALTER TABLE [dbo].[sup_cust_conn]  WITH CHECK ADD  CONSTRAINT [FK_sup_cust_conn_suppliers] FOREIGN KEY([supplierId])
REFERENCES [dbo].[suppliers] ([supplierId])
GO
ALTER TABLE [dbo].[sup_cust_conn] CHECK CONSTRAINT [FK_sup_cust_conn_suppliers]


Var det det du skulle bruge?

Skrevet ons. d. 05. december 2007 kl. 22:51:55| #19

janus_007
janus_007 (30.915 point)
Okay.. jeg har indsat noget testdata:
insert into prodCats values(3, 'Varmesystemer', 'content1', 0, 30, 0)
insert into prodCats values(1, 'Badeværelset', 'content2', 0, 10, 0)

insert into products values(1000, 'Oliefyr', 'of', 10, 3, 1, 0)
insert into products values(900, 'Vandvarmer', 'vv', 20, 3, 2, 0)
insert into products values(700, 'Vandhane', 'vh', 10, 1, 1, 0)

insert into sup_cust_conn (supplierid, customerid) values(5, 5)

Det eneste jeg lige kan komme på er fordi den innerste joiner op på products og så er det jo egentlig klart nok at den giver så mange rækker, 1 række for hvert produkt.

SELECT *
    FROM prodCats pcs
inner join (SELECT distinct prodCatBelongsTo FROM prodCats p1_inner
        inner join products p2
            on p2.prodCatId = p1_inner.prodCatId
        inner join sup_cust_conn s
            on s.supplierId = p2.supplierId
                where s.customerId = 5) as p
on p.prodCatBelongsTo = pcs.prodCatId

Jeg vil mene du skal bruge en distinct på p1_inner clausen, det er må betragtes som et af de tilfælde hvor distinct er tilladt, det sker til alt held kun på en integer kolonne hvilket ikke burde give anledning til performance issues...

Dvs. det skal se sådan her ud:
WITH prodCatsCTE(prodCatId, prodCatName, prodCatBelongsTo, prodCatOrderNr, depth, sortcol) 
    AS 
    ( 
SELECT pcs.prodCatId, pcs.prodCatName, pcs.prodCatBelongsTo, pcs.prodCatOrderNr, 0, CAST(pcs.prodCatId AS VARBINARY(900)) 
    FROM prodCats pcs
inner join (SELECT DISTINCT prodCatBelongsTo FROM prodCats p1_inner
        inner join products p2
            on p2.prodCatId = p1_inner.prodCatId
        inner join sup_cust_conn s
            on s.supplierId = p2.supplierId
                where s.customerId = 5) as p
on p.prodCatBelongsTo = pcs.prodCatId
)
SELECT REPLICATE('    ', depth) + prodCatName AS prodCatName, prodCatId, prodCatBelongsTo, prodCatOrderNr, depth 
    FROM prodCatsCTE 
    ORDER BY sortcol

Jeg tror ikke jeg kan komme det meget nærmere, endsige bedre :)

Du kan evt. teste forskellen imellem do. og så din where in... skriv i din query analyzer:
SET STATISTICS IO ON
og sammenlign :-)


Håber du kan bruge det.

Skrevet tor. d. 06. december 2007 kl. 09:57:35| #20

donkazz
donkazz (11.670 point)
Aaaah.... Perfekt!! Det virker jo! :-))

Så skal vi bare have koblet den der union all på som vi fjernede i starten.. ;)

    UNION ALL 
    SELECT p.prodCatId, p.prodCatName, p.prodCatBelongsTo, p.prodCatOrderNr, pc.depth+1, 
    CAST(sortcol + CAST(p.prodCatOrderNr AS BINARY(4)) AS VARBINARY(900)) 
    FROM prodCats p 
    JOIN prodCatsCTE AS pc 
    ON p.prodCatBelongsTo = pc.prodCatId 
    WHERE pc.prodCatId = p.prodCatBelongsTo 
    AND p.prodCatId IN 
            (SELECT pro.prodCatId FROM products pro INNER JOIN prodCats pp ON pro.prodCatId=pp.prodCatId WHERE pro.supplierId IN 
                (SELECT supplierId FROM sup_cust_conn WHERE customerId =  @customerId) 
            AND pp.prodCatBelongsTo = pc.prodCatId) 
    AND 
    pc.prodCatId =  @selectedId 
    OR 
    (pc.prodCatId = (SELECT prodCatBelongsTo FROM prodCats WHERE prodCatId =  @selectedId )     
    AND p.prodCatId IN 
            (SELECT pro.prodCatId FROM products pro INNER JOIN prodCats pp ON pro.prodCatId=pp.prodCatId WHERE pro.supplierId IN 
                (SELECT supplierId FROM sup_cust_conn WHERE customerId =  @customerId) 
            AND pp.prodCatBelongsTo = pc.prodCatId))     
    )

:D

Skrevet tor. d. 06. december 2007 kl. 23:35:37| #21

janus_007
janus_007 (30.915 point)
arrghh fuck.. den havde jeg lykkeligt glemt hehe. Men jeg forstår det hele meget bedre nu, håber jeg da.

Well.. men den skal jo næsten også omskrives til joins. Kunne vi starte med:

SELECT p.prodCatId, p.prodCatName, p.prodCatBelongsTo, p.prodCatOrderNr, pc.depth+1, 
    CAST(sortcol + CAST(p.prodCatOrderNr AS BINARY(4)) AS VARBINARY(900)) 
    FROM prodCats p 
    INNER JOIN prodCatsCTE AS pc 
    ON p.prodCatBelongsTo = pc.prodCatId 
    AND pc.prodCatId = p.prodCatBelongsTo 
    INNER JOIN (SELECT pro.prodCatId FROM products pro
                INNER JOIN prodCats pp
                    ON pro.prodCatId=pp.prodCatId
                INNER JOIN sup_cust_conn scc
                    ON scc.supplierId = pro.supplierId
                    WHERE customerId =  5) as p_inner
    ON p_inner.prodCatId = pp.prodCatBelongsTo

Og så se hvad den giver.

Jeg har ikke lige create table til prodCatsCTE.

Skrevet fre. d. 07. december 2007 kl. 08:38:59| #22

donkazz
donkazz (11.670 point)
Jeg rettede sidste linje og så virker det sådan nogenlunde, men hvor fletter jeg @selectedId ind henne? Hvis nu @selectedId = 1 så skal den jo udvide "1 Badeværelset" så man kan se de dertilhørende prodCats samtidigt med at man stadig skal kunne se de andre prodCats where prodCatBelongsTo = 0... :-O

Skrevet fre. d. 07. december 2007 kl. 12:30:55| #23

donkazz
donkazz (11.670 point)
Jeg prøvede den her som NÆSTEN virker efter hensigten, dog kommer prodCats p ud tilsvarende antal produkter prodCat'en har...

WITH prodCatsCTE(prodCatId, prodCatName, prodCatBelongsTo, prodCatOrderNr, depth, sortcol) 
    AS 
    ( 
SELECT pcs.prodCatId, pcs.prodCatName, pcs.prodCatBelongsTo, pcs.prodCatOrderNr, 0, CAST(pcs.prodCatId AS VARBINARY(900)) 
    FROM prodCats pcs
inner join (SELECT DISTINCT prodCatBelongsTo FROM prodCats p1_inner
        inner join products p2
            on p2.prodCatId = p1_inner.prodCatId
        inner join sup_cust_conn s
            on s.supplierId = p2.supplierId
                where s.customerId = 5) as p
on p.prodCatBelongsTo = pcs.prodCatId
WHERE pcs.prodCatBelongsTo = 0
UNION ALL
SELECT p.prodCatId, p.prodCatName, p.prodCatBelongsTo, p.prodCatOrderNr, pc.depth+1, 
    CAST(sortcol + CAST(p.prodCatOrderNr AS BINARY(4)) AS VARBINARY(900)) 
    FROM prodCats p 
    INNER JOIN prodCatsCTE AS pc 
    ON p.prodCatBelongsTo = pc.prodCatId
    INNER JOIN products pro ON p.prodCatId=pro.prodCatId
    INNER JOIN sup_cust_conn scc ON pro.supplierId=scc.supplierID
p.prodCatId = p_inner.prodCatId
    WHERE pc.prodCatId = p.prodCatBelongsTo AND scc.customerId = 5
)
SELECT REPLICATE('    ', depth) + prodCatName AS prodCatName, prodCatId, prodCatBelongsTo, prodCatOrderNr, depth 
    FROM prodCatsCTE 
    ORDER BY sortcol

Giver følgende:

Badeværelset    1    0    10    0
    Sanitet    4    1    10    1
    Armaturer & Batterier    5    1    20    1
    Armaturer & Batterier    5    1    20    1
    Armaturer & Batterier    5    1    20    1
    Brus & Kar    6    1    30    1
Varmesystemer    3    0    30    0
    Gaskedler    16    3    10    1


:-O ?

Skrevet fre. d. 07. december 2007 kl. 12:32:01| #24

donkazz
donkazz (11.670 point)
Selvfølgelig virker det med følgende til sidst

SELECT DISTINCT REPLICATE('    ', depth) + prodCatName AS prodCatName, sortcol, prodCatId, prodCatBelongsTo, prodCatOrderNr, depth 
    FROM prodCatsCTE 
    ORDER BY sortcol

men var der noget med at DISTINCT var fy fy? :-D

Skrevet fre. d. 07. december 2007 kl. 14:05:25| #25

janus_007
janus_007 (30.915 point)
Ja vi vil helst undgå distinct på flere kolonner, det er ok at anvende distinct på en enkelt kolonne og helst på int, smallint osv.

Jeg kunne godt tænke mig vi holdt fast i fidusen med et sub inner join products, årsagen er at der kan være mange produkter med samme prodCatId og det vil nemlig give dubletter.

Så kunne du forsøge at arbejde videre med den her fra tidligere? (jeg har tilføjet DISTINCT til subjoin.

SELECT p.prodCatId, p.prodCatName, p.prodCatBelongsTo, p.prodCatOrderNr, pc.depth+1, 
    CAST(sortcol + CAST(p.prodCatOrderNr AS BINARY(4)) AS VARBINARY(900)) 
    FROM prodCats p 
    INNER JOIN prodCatsCTE AS pc 
    ON p.prodCatBelongsTo = pc.prodCatId 
      AND pc.prodCatId =  @selectedId
    INNER JOIN (SELECT DISTINCT pro.prodCatId FROM products pro
                INNER JOIN prodCats pp
                    ON pro.prodCatId=pp.prodCatId
                INNER JOIN sup_cust_conn scc
                    ON scc.supplierId = pro.supplierId
                    WHERE customerId = 5) as p_inner
    ON p_inner.prodCatId = pp.prodCatBelongsTo



Jeg vil mene @selectedId skal stå der :) , det er ikke nemt uden data det her hehe...

Skrevet fre. d. 07. december 2007 kl. 16:12:19| #26

donkazz
donkazz (11.670 point)
Msg 4104, Level 16, State 1, Line 1
The multi-part identifier "pp.prodCatBelongsTo" could not be bound.
Msg 460, Level 16, State 1, Line 1
DISTINCT operator is not allowed in the recursive part of a recursive common table expression 'prodCatsCTE

Hvad betyder det? :-O

Skrevet lør. d. 08. december 2007 kl. 14:07:35| #27

janus_007
janus_007 (30.915 point)
En lille fejl havde sneget sig ind, jeg skrev pp. der skal stå p

SELECT p.prodCatId, p.prodCatName, p.prodCatBelongsTo, p.prodCatOrderNr, pc.depth+1, 
    CAST(sortcol + CAST(p.prodCatOrderNr AS BINARY(4)) AS VARBINARY(900)) 
    FROM prodCats p 
    INNER JOIN prodCatsCTE AS pc 
    ON p.prodCatBelongsTo = pc.prodCatId 
      AND pc.prodCatId =  @selectedId
    INNER JOIN (SELECT DISTINCT pro.prodCatId FROM products pro
                INNER JOIN prodCats pp
                    ON pro.prodCatId=pp.prodCatId
                INNER JOIN sup_cust_conn scc
                    ON scc.supplierId = pro.supplierId
                    WHERE customerId = 5) as p_inner
    ON p_inner.prodCatId = p.prodCatBelongsTo

Skrevet tir. d. 11. december 2007 kl. 11:25:54| #28

donkazz
donkazz (11.670 point)
Den bliver ved med at sige:

DISTINCT operator is not allowed in the recursive part of a recursive common table expression 'prodCatsCTE'.

Hmmm... hvad faen?

Skrevet søn. d. 23. december 2007 kl. 16:02:38| #29

janus_007
janus_007 (30.915 point)
uha.. havde helt glemt denne tråd :-( Beklager...

Ja... hvad er det da for noget, jeg tror den bedste måde at løse det på må være at du sender mig table definition på prodCatsCTE


God Jul :-)

Skrevet fre. d. 28. december 2007 kl. 10:06:12| #30

donkazz
donkazz (11.670 point)
Altså prodCatsCTE er jo den første tabel vi definerer, er det ikke? Det er ikke en jeg har liggende i databasen, så det må være en temp tabel eller noget..?

Ja god Jul og godt nytår ;)

Skrevet tor. d. 07. februar 2008 kl. 09:54:30| #31


Skriv et indlæg




Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] [img]link til billede[/img]
Web- og emailadresser omdannes automatisk til links

Log ind

   

   

Seneste spørgsmål

Stored procedure og triggers

Oprettet den 22. maj 2012 kl. 10.11
htm giver 60 point for svar | Giv et svar »

SELECT by NEWID

Oprettet den 14. maj 2012 kl. 10.21
zentral giver 200 point for svar | Giv et svar »

Hvor finder jeg logfiler?

Oprettet den 14. maj 2012 kl. 10.07
hundevennen giver 100 point for svar | Giv et svar »



   




Tips & Tricks fra PC World

Teaser billede

Læserne: Her er vores værste it-indkøb

Det er ikke al it-udstyr, som er det rene guld. Her er nogle af læsernes skrækhistorier.


Anmeldelser fra PC World

Teaser billede

Test: Mobil med Ferrari-design - og en Trabant-motor

Motorola har begået endnu en smartphone med lækkert design og potentiale til at være blandt de bedste. Men den når ikke i mål. Se her hvorfor.


Seneste blogindlæg

Teaser billede

Tvangslukke spørgsmål: Hvad er den bedste løsning?

Hej Vi har mange åbne spørgsmål på Eksperten. Vi ville gerne tvangslukke dem - så et spørgsmål efter f.eks. 6 måneder lukkes. Men der er et par uklarheder som ville være gode at få lidt input til:...


Nyheder fra PC World

Teaser billede

Sådan siger du farvel til Facebook

Læs her, hvordan du dropper Facebook og i stedet anvender nogle brugervenlige alternativer, så du stadig kan være social på nettet.


Nyheder fra Computerworld

Teaser billede

Galleri: De fedeste håndholdte gennem 40 år

Her har du de mest banebrydende håndholdte computere gennem alle tider.


Kurser
Samarbejdspartnere

Udgiver · © 2012 IDG Danmark A/S · Hørkær 18 · 2730 Herlev · Tlf.: 77 300 300 · Fax: 77 300 301 · Brug af personoplysninger