Is INTERSECTS the best method to accomplish this?

  • I a typical Customer order scenario, there is a header record and one or more lines records per header. (If you would like sample files to create a table and insert records, just ask. I am thinking this is so common that would not be necessary. But if it is needed, please let me know).

    I am looking for a way to return all the orders that contain several items. Let's say the items are A,B and C. I want all order numbers that contain all three items. I do not want an order that only contains one or two of the items.

    At the moment the following query does work.

    Select OrdNo From OrdLine

    where ItemNo = 'A'

    Intersects

    Select OrdNo From OrdLine

    where ItemNo = 'B'

    Intersects

    Select OrdNo From OrdLine

    where ItemNo = 'C'

    Is there another way of returning the unique order numbers that contain all three Item numbers?

    Thanks,

    pat

  • If i am not Wrong, i hope this may be the query, U need

    Select OrdNo From OrdLine

    where ItemNo = 'A'

    UNION

    Select OrdNo From OrdLine

    where ItemNo = 'B'

    UNION

    Select OrdNo From OrdLine

  • suggest you read the following article on this site....

    http://www.sqlservercentral.com/articles/T-SQL/88244/

    hope it helps.

    ________________________________________________________________
    you can lead a user to data....but you cannot make them think
    and remember....every day is a school day

  • Bhu1 (7/9/2012)


    If i am not Wrong, i hope this may be the query, U need

    Select OrdNo From OrdLine

    where ItemNo = 'A'

    UNION

    Select OrdNo From OrdLine

    where ItemNo = 'B'

    UNION

    Select OrdNo From OrdLine

    Sorry, but this is wrong query. Please verify answer before creating a sample table.He needs the order those are having all three items A,B,C.

    --rhythmk
    ------------------------------------------------------------------
    To post your question use below link

    https://www.sqlservercentral.com/articles/forum-etiquette-how-to-post-datacode-on-a-forum-to-get-the-best-help
    🙂

  • mpdillon (7/8/2012)


    I a typical Customer order scenario, there is a header record and one or more lines records per header. (If you would like sample files to create a table and insert records, just ask. I am thinking this is so common that would not be necessary. But if it is needed, please let me know).

    I am looking for a way to return all the orders that contain several items. Let's say the items are A,B and C. I want all order numbers that contain all three items. I do not want an order that only contains one or two of the items.

    At the moment the following query does work.

    Select OrdNo From OrdLine

    where ItemNo = 'A'

    Intersects

    Select OrdNo From OrdLine

    where ItemNo = 'B'

    Intersects

    Select OrdNo From OrdLine

    where ItemNo = 'C'

    Is there another way of returning the unique order numbers that contain all three Item numbers?

    Thanks,

    pat

    Sorry but again what you can see we can't see at our end.

    So to help you please help us by providing sample data.

    The only purpose for that to know how the records reside in the table.

    --rhythmk
    ------------------------------------------------------------------
    To post your question use below link

    https://www.sqlservercentral.com/articles/forum-etiquette-how-to-post-datacode-on-a-forum-to-get-the-best-help
    🙂

  • Without some DDL and sample data I can't post a tested solution but something like this may work (INTERSECT the way you've written it should except you misspelled the keyword):

    Select OrdNo

    From OrdLine

    where ItemNo IN ('A', 'B', 'C')

    GROUP BY OrdNo, ItemNo

    HAVING COUNT(ItemNo) = 3

    Note that if your order can contain item A more than once, then simply COUNT the DISTINCT ItemNo.


    My mantra: No loops! No CURSORs! No RBAR! Hoo-uh![/I]

    My thought question: Have you ever been told that your query runs too fast?

    My advice:
    INDEXing a poor-performing query is like putting sugar on cat food. Yeah, it probably tastes better but are you sure you want to eat it?
    The path of least resistance can be a slippery slope. Take care that fixing your fixes of fixes doesn't snowball and end up costing you more than fixing the root cause would have in the first place.

    Need to UNPIVOT? Why not CROSS APPLY VALUES instead?[/url]
    Since random numbers are too important to be left to chance, let's generate some![/url]
    Learn to understand recursive CTEs by example.[/url]
    [url url=http://www.sqlservercentral.com/articles/St

  • Try something like this.

    select count(ordno) from

    (

    select OrdNo,

    sum(distinct(case when ItemNo = 'A' then 1 when ItemNo = 'B' then 2 when ItemNo = 'C' then 4 end)) as status

    from OrdLine

    where ItemNo IN ('A', 'B', 'C')

    group by OrdNo

    ) dta

    where

    1=1

    --and status = 3 -- a,b but not c

    --and status = 5--does have a,c but not b

    --and status = 6--does have b,c but not a

    and status = 7 --all 3

    --and status = 0 --none of them

    --and status = 1 -- just A

    --and status = 2 -- just b

    --and status = 4 -- just C

    GulliMeel

    Finding top n Worst Performing queries[/url]
    Improve the performance of Merge Join(special case)
    How to Post Performance Problem -Gail Shaw[/url]

  • Gullimeel (7/9/2012)


    Try something like this.

    --change the id with ordno and cd with product code

    select * from

    (

    select id,

    max(case when cd = 'A' then 1 else 0 end) +

    max(case when cd = 'B' then 2 else 0 end) +

    max(case when cd = 'C' then 4 else 0 end) as status

    from a

    --where cd in ('A','B','C')

    group by id

    ) dta

    where

    1=1

    --and status = 3 -- a,b but not c

    --and status = 5--does have a,c but not b

    --and status = 6--does have b,c but not a

    and status = 7 --all 3

    --and status = 0 --none of them

    --and status = 1 -- just A

    --and status = 2 -- just b

    --and status = 4 -- just C

    How about the performance - better than the query posted by OP ?

    --rhythmk
    ------------------------------------------------------------------
    To post your question use below link

    https://www.sqlservercentral.com/articles/forum-etiquette-how-to-post-datacode-on-a-forum-to-get-the-best-help
    🙂

  • Thanks for the input.

    Here is the code to create a table and populate it.

    SET ANSI_NULLS ON

    GO

    SET QUOTED_IDENTIFIER ON

    GO

    SET ANSI_PADDING ON

    GO

    CREATE TABLE [dbo].[OrdLine](

    [OrdNo] [int] NULL,

    [ItemNo] [varchar](50) NULL

    ) ON [PRIMARY]

    GO

    SET ANSI_PADDING OFF

    GO

    Add data:

    Insert into OrdLine (OrdNo,ItemNo)

    select 1,'A'

    Union all

    Select 1,'B'

    Union all

    select 1,'C'

    union all

    select 2,'A'

    Union all

    Select 2,'B'

    Union all

    select 3,'C'

    union all

    select 4,'D'

    Union all

    Select 4,'B'

    Union all

    select 4,'C'

    Thanks,

    pat

  • Gullimeel (7/9/2012)

    --------------------------------------------------------------------------------

    Try something like this.

    --change the id with ordno and cd with product code

    select * from

    (

    select id,

    max(case when cd = 'A' then 1 else 0 end) +

    max(case when cd = 'B' then 2 else 0 end) +

    max(case when cd = 'C' then 4 else 0 end) as status

    from a

    --where cd in ('A','B','C')

    group by id

    ) dta

    where

    1=1

    --and status = 3 -- a,b but not c

    --and status = 5--does have a,c but not b

    --and status = 6--does have b,c but not a

    and status = 7 --all 3

    --and status = 0 --none of them

    --and status = 1 -- just A

    --and status = 2 -- just b

    --and status = 4 -- just C

    How about the performance - better than the query posted by OP ?

    --rhythmk

    Give it a try..if you feel it is not performing better then let me know 🙂

    GulliMeel

    Finding top n Worst Performing queries[/url]
    Improve the performance of Merge Join(special case)
    How to Post Performance Problem -Gail Shaw[/url]

  • A slight modification to dwain.c's solution works and seems simple enough.

    --Remove ItemNo from the Group By

    Select OrdNo

    From OrdLine

    where ItemNo IN ('A', 'B', 'C')

    GROUP BY OrdNo

    HAVING COUNT(ItemNo) = 3

    Thank you,

    pat

  • Gullimeel,

    I receive an error, "Invalid object name 'a' ".

    If the ItemNo is removed from the Group By in dwain.c's solution, the correct order number is returned.

    Thanks,

    pat

  • You have to change that query..I just used a table a.Change it as per your requirement... like a will be your table name,id will be ordno and cd will be itemno..

    GulliMeel

    Finding top n Worst Performing queries[/url]
    Improve the performance of Merge Join(special case)
    How to Post Performance Problem -Gail Shaw[/url]

  • Try it with a million invoices (3M detail rows):

    CREATE TABLE #OrdLine([OrdNo] [int] NULL,[ItemNo] [varchar](50) NULL) ON [PRIMARY]

    ;WITH Tally (n) AS (

    SELECT TOP 1000000 ROW_NUMBER() OVER (ORDER BY (SELECT NULL))

    FROM sys.all_columns c1 CROSS JOIN sys.all_columns c2)

    INSERT INTO #OrdLine

    SELECT OrdNo=n, ItemNo

    FROM Tally

    CROSS APPLY (SELECT 'A' UNION ALL SELECT 'B' UNION ALL SELECT 'C') a(ItemNo)

    PRINT '--- OP''s query'

    SET STATISTICS TIME ON

    Select OrdNo From #OrdLine

    where ItemNo = 'A'

    Intersect

    Select OrdNo From #OrdLine

    where ItemNo = 'B'

    Intersect

    Select OrdNo From #OrdLine

    where ItemNo = 'C'

    SET STATISTICS TIME OFF

    PRINT '--- Dwain''s query'

    SET STATISTICS TIME ON

    Select OrdNo

    From #OrdLine

    where ItemNo IN ('A', 'B', 'C')

    GROUP BY OrdNo

    HAVING COUNT(ItemNo) = 3

    SET STATISTICS TIME OFF

    PRINT '--- Gullimeel''s query'

    SET STATISTICS TIME ON

    --change the id with ordno and cd with product code

    select * from

    (

    select OrdNo,

    max(case when ItemNo = 'A' then 1 else 0 end) +

    max(case when ItemNo = 'B' then 2 else 0 end) +

    max(case when ItemNo = 'C' then 4 else 0 end) as status

    from #OrdLine

    --where cd in ('A','B','C')

    group by OrdNo

    ) dta

    where

    1=1

    --and status = 3 -- a,b but not c

    --and status = 5--does have a,c but not b

    --and status = 6--does have b,c but not a

    and status = 7 --all 3

    --and status = 0 --none of them

    --and status = 1 -- just A

    --and status = 2 -- just b

    --and status = 4 -- just C

    SET STATISTICS TIME OFF

    DROP TABLE #OrdLine

    A minor fix to my query returned these results:

    (3000000 row(s) affected)

    --- OP's query

    (1000000 row(s) affected)

    SQL Server Execution Times:

    CPU time = 6132 ms, elapsed time = 7305 ms.

    --- Dwain's query

    (1000000 row(s) affected)

    SQL Server Execution Times:

    CPU time = 3791 ms, elapsed time = 9540 ms.

    --- Gullimeel's query

    (1000000 row(s) affected)

    SQL Server Execution Times:

    CPU time = 5523 ms, elapsed time = 8920 ms.


    My mantra: No loops! No CURSORs! No RBAR! Hoo-uh![/I]

    My thought question: Have you ever been told that your query runs too fast?

    My advice:
    INDEXing a poor-performing query is like putting sugar on cat food. Yeah, it probably tastes better but are you sure you want to eat it?
    The path of least resistance can be a slippery slope. Take care that fixing your fixes of fixes doesn't snowball and end up costing you more than fixing the root cause would have in the first place.

    Need to UNPIVOT? Why not CROSS APPLY VALUES instead?[/url]
    Since random numbers are too important to be left to chance, let's generate some![/url]
    Learn to understand recursive CTEs by example.[/url]
    [url url=http://www.sqlservercentral.com/articles/St

  • mpdillon (7/9/2012)


    A slight modification to dwain.c's solution works and seems simple enough.

    --Remove ItemNo from the Group By

    Select OrdNo

    From OrdLine

    where ItemNo IN ('A', 'B', 'C')

    GROUP BY OrdNo

    HAVING COUNT(ItemNo) = 3

    Thank you,

    pat

    As per your table DDL, use DISTINCT as suggested by dwain to avoid failure because of duplicate values.

    i.e.

    Select OrdNo

    From OrdLine

    where ItemNo IN ('A', 'B', 'C')

    GROUP BY OrdNo

    HAVING COUNT(DISTINCT ItemNo) = 3

    --rhythmk
    ------------------------------------------------------------------
    To post your question use below link

    https://www.sqlservercentral.com/articles/forum-etiquette-how-to-post-datacode-on-a-forum-to-get-the-best-help
    🙂

Viewing 15 posts - 1 through 15 (of 17 total)

You must be logged in to reply to this topic. Login to reply