Cross join query help

  • I have following tables

    Hub_Details (Master)

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

    Branch_ID

    Branch_Name

    VTRCheckList (Master)

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

    CLid

    CLName

    VTRCheckListDetails (Detail)

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

    CLid

    Branch_ID

    vtrvalue

    vtrRespDate

    Wanted the data to be populated with all the branches exists in Hub_Details and show the checklist names alongwith the branches with the sum of vtrvalue field.

    i have created this query

    select r.CLName, p.BranchName, ISNULL(sum(cast(s.vtrvalue as int)),0)

    from VTRCheckList r

    cross join Hub_Details p

    left outer join VTRCheckListDetails s on s.CLid = r.CLid

    and s.branchid = p.BranchID

    --WHERE Convert(date,s.vtrRespDate, 105) >= convert(date,'01-01-2011',105) and Convert(date, s.vtrRespDate, 105) <= convert(date,'29-01-2011',105)

    group by r.CLName, p.BranchName

    order by r.CLName, p.BranchName

    END

    that shows e.g. total vtrvalues by CheckListName and BranchName. If no inputs were made in CheckListName in any Branch then we want to see a row with a zero, rather than just not showing a row.

    This query is working great but when put the where clause to check all the branches position in between dates it shows only the branch which meets the criteria. I want to show all the branches no matter which criteria i put it in. If i remove "and s.branchid = p.branchID" it comes with all branches but the vtrvalue repeats their values in all branches.

    Any help?

    thanks

  • ive solved my problem 🙂

  • joshtheflame (1/8/2011)


    ive solved my problem 🙂

    Cool... What did you do to fix it?

    --Jeff Moden


    RBAR is pronounced "ree-bar" and is a "Modenism" for Row-By-Agonizing-Row.
    First step towards the paradigm shift of writing Set Based code:
    ________Stop thinking about what you want to do to a ROW... think, instead, of what you want to do to a COLUMN.

    Change is inevitable... Change for the better is not.


    Helpful Links:
    How to post code problems
    How to Post Performance Problems
    Create a Tally Function (fnTally)

  • this is what i did. the WHERE condition was the problem which was filtering right after grouping so removed where thats it:)

    DECLARE @startDate varchar(20)

    DECLARE @endDate varchar(20)

    SELECT @startDate = Convert(varchar(10),DATEADD(m, @Month - 1, DATEADD(yyyy, @Year - 1900, 0)),105)

    SELECT @endDate = Convert(varchar(10),DATEADD(d, -1, DATEADD(m, @Month, DATEADD(yyyy, @Year - 1900, 0))),105)

    SELECT r.CLName, p.BranchName, ISNULL(sum(cast(s.vtrvalue as int)),0) FROM VTRCheckList r

    CROSS JOIN Hub_Details p

    LEFT OUTER JOIN VTRCheckListDetails s ON s.CLid = r.CLid AND s.branchid = p.BranchID

    AND Convert(date,s.vtrRespDate, 105) >= convert(date,@startDate,105) and Convert(date, s.vtrRespDate, 105) <= convert(date,@endDate,105)

    GROUP BY r.CLName, p.BranchName

    ORDER BY r.CLName, p.BranchName

  • A few things to notice:

    When running queries against datetime values stored in your db you should not convert those values to varchar in order to do any comparison. This will prevent SQL Server from using any index so you'll end with a table scan that migt cause a major performance decrease.

    Even if you need to convert it, don't use a format that doesn't maintain the order of dates.

    You convert it to a dd-mm-yy format. This will return wrong results as soon as you're dealing with a time span of outside a single month.

    Maybe the following will be more efficient:

    AND s.vtrRespDate>= CAST(@Year+@Month+'01' AS DATE) AND s.vtrRespDate< DATEADD(mm,1,CAST(@Year+@Month+'01'))



    Lutz
    A pessimist is an optimist with experience.

    How to get fast answers to your question[/url]
    How to post performance related questions[/url]
    Links for Tally Table [/url] , Cross Tabs [/url] and Dynamic Cross Tabs [/url], Delimited Split Function[/url]

  • joshtheflame (1/9/2011)


    this is what i did. the WHERE condition was the problem which was filtering right after grouping so removed where thats it:)

    DECLARE @startDate varchar(20)

    DECLARE @endDate varchar(20)

    SELECT @startDate = Convert(varchar(10),DATEADD(m, @Month - 1, DATEADD(yyyy, @Year - 1900, 0)),105)

    SELECT @endDate = Convert(varchar(10),DATEADD(d, -1, DATEADD(m, @Month, DATEADD(yyyy, @Year - 1900, 0))),105)

    SELECT r.CLName, p.BranchName, ISNULL(sum(cast(s.vtrvalue as int)),0) FROM VTRCheckList r

    CROSS JOIN Hub_Details p

    LEFT OUTER JOIN VTRCheckListDetails s ON s.CLid = r.CLid AND s.branchid = p.BranchID

    AND Convert(date,s.vtrRespDate, 105) >= convert(date,@startDate,105) and Convert(date, s.vtrRespDate, 105) <= convert(date,@endDate,105)

    GROUP BY r.CLName, p.BranchName

    ORDER BY r.CLName, p.BranchName

    Lutz is correct.... you're going to not only have performance problems because of the date conversions you've done but you're also going to get incorrect answers because you've selected a non-sortable date format.

    --Jeff Moden


    RBAR is pronounced "ree-bar" and is a "Modenism" for Row-By-Agonizing-Row.
    First step towards the paradigm shift of writing Set Based code:
    ________Stop thinking about what you want to do to a ROW... think, instead, of what you want to do to a COLUMN.

    Change is inevitable... Change for the better is not.


    Helpful Links:
    How to post code problems
    How to Post Performance Problems
    Create a Tally Function (fnTally)

  • Lutz and Jeff,

    I have only date datatype not time as I dont need time stored in table. Although i always find a problem regarding date formats. I want to keep dd/mm/yyyy so even though if i take datetime datatype what is the correct way of passing date string in procedure and compare against the start date and end date if time is also included (I have no concern with the time).

    thanks for guiding me in the right direction guys. you guys rock.

  • SQL Server will recognize a lot of date formatted strings. If you declare a date variable you can simply assign to it from one of those correctly formatted string formats. For this reason you should keep your datetime columns and variables declared as dates. You should, however, stick to formats that are not ambiguous just for your own safety. eg:

    create table T(some_date datetime)

    declare @my_date datetime

    set @my_date = '20110116' -- ISO format always safe, ymd implied. Sorts correctly as varchar

    set @my_date = '110116' -- ISO format always safe, ymd implied. Sorts correctly as varchar

    set @my_date = '2011-01-16' -- surprisingly not safe unless set dateformat ymd! Sorts correctly as varchar

    set @my_date = '16 jan 2011' -- alphabetic months are always safe. Not always going to sort correctly as varchar

    set @my_date = '16 jan 11' -- as above

    set @my_date = '2011 jan 16' -- as above

    set @my_date = '11/1/16' -- unsafe and ambiguous and probably won't sort correctly as varchar. DO NOT USE

    set @my_date = '1/11/16' -- as above

    set @my_date = '2011-01-16T20:15:00' -- ISO 8601. THE safest format, everything explicit, sorts correctly as varchar

    select @my_date

    insert T select @my_date

    -- in the following line the strings will be implicitly converted to datetime before sql server does the comparison

    select * from T where some_date >= '1 jan 2011' and some_date < '1 feb 2011'

  • @allmhuran:

    I disagree with your statement "-- alphabetic months are always safe."

    Alphabetic months depend on the language setting. Therefore, I won't consider this format as being safe by any means.

    Simply run the following code:

    SET LANGUAGE german

    DECLARE @my_date DATETIME

    SET @my_date = '16 oct 2011'



    Lutz
    A pessimist is an optimist with experience.

    How to get fast answers to your question[/url]
    How to post performance related questions[/url]
    Links for Tally Table [/url] , Cross Tabs [/url] and Dynamic Cross Tabs [/url], Delimited Split Function[/url]

  • HAH! Quite true I suppose. Not a problem you're likely ever to run into though, unless for some reason you decide to develop in a different language for the lulz. I mean, a German programmer using set language german would probably use a German string, neh? 🙂

    (edit: yeah yeah, portability, blah blah blah 😉 )

  • allmhuran (1/15/2011)


    HAH! Quite true I suppose. Not a problem you're likely ever to run into though, unless for some reason you decide to develop in a different language for the lulz. I mean, a German programmer using set language german would probably use a German string, neh? 🙂

    (edit: yeah yeah, portability, blah blah blah 😉 )

    I'm not only talking about portablility. It's enough to add a user with a different language setting. Think about English and French in Canada or English and Spanish in some other regions.

    And that's nothing you would be made aware of as a developer... You'd just be asked to deal with the consequences. 😉



    Lutz
    A pessimist is an optimist with experience.

    How to get fast answers to your question[/url]
    How to post performance related questions[/url]
    Links for Tally Table [/url] , Cross Tabs [/url] and Dynamic Cross Tabs [/url], Delimited Split Function[/url]

  • Good point. That would cause problems with check constraints, defaults, etc too....

    So the lesson is stick with an ISO format! Well, I always have anyway.

  • joshtheflame (1/15/2011)


    Lutz and Jeff,

    I have only date datatype not time as I dont need time stored in table. Although i always find a problem regarding date formats. I want to keep dd/mm/yyyy so even though if i take datetime datatype what is the correct way of passing date string in procedure and compare against the start date and end date if time is also included (I have no concern with the time).

    thanks for guiding me in the right direction guys. you guys rock.

    Understood. Just be aware that sorting will always be a bitch as will any type of date math. I've had lot's of folks do the same as you for the same reasons and they always end up suffering with code and performance problems further on down the line.

    --Jeff Moden


    RBAR is pronounced "ree-bar" and is a "Modenism" for Row-By-Agonizing-Row.
    First step towards the paradigm shift of writing Set Based code:
    ________Stop thinking about what you want to do to a ROW... think, instead, of what you want to do to a COLUMN.

    Change is inevitable... Change for the better is not.


    Helpful Links:
    How to post code problems
    How to Post Performance Problems
    Create a Tally Function (fnTally)

  • joshtheflame (1/9/2011)


    this is what i did. the WHERE condition was the problem which was filtering right after grouping so removed where thats it:)

    DECLARE @startDate varchar(20)

    DECLARE @endDate varchar(20)

    SELECT @startDate = Convert(varchar(10),DATEADD(m, @Month - 1, DATEADD(yyyy, @Year - 1900, 0)),105)

    SELECT @endDate = Convert(varchar(10),DATEADD(d, -1, DATEADD(m, @Month, DATEADD(yyyy, @Year - 1900, 0))),105)

    SELECT r.CLName, p.BranchName, ISNULL(sum(cast(s.vtrvalue as int)),0) FROM VTRCheckList r

    CROSS JOIN Hub_Details p

    LEFT OUTER JOIN VTRCheckListDetails s ON s.CLid = r.CLid AND s.branchid = p.BranchID

    AND Convert(date,s.vtrRespDate, 105) >= convert(date,@startDate,105) and Convert(date, s.vtrRespDate, 105) <= convert(date,@endDate,105)

    GROUP BY r.CLName, p.BranchName

    ORDER BY r.CLName, p.BranchName

    First comment: in SQL Server 2008 there have been improvements that allow for converting a column to a date and still able to use indexes.

    Second comment: you don't need to worry about this, and the converts are just causing additional processing to be performed.

    In your query, you are converting a column that should already be a date data type to a date data type. Then, you are converting your string parameter to a date where you should define that parameter as a date in the first place.

    If you change this:

    DECLARE @startDate varchar(20)

    DECLARE @endDate varchar(20)

    SELECT @startDate = Convert(varchar(10),DATEADD(m, @Month - 1, DATEADD(yyyy, @Year - 1900, 0)),105)

    SELECT @endDate = Convert(varchar(10),DATEADD(d, -1, DATEADD(m, @Month, DATEADD(yyyy, @Year - 1900, 0))),105)

    To this:

    DECLARE @startDate date = DATEADD(m, @Month - 1, DATEADD(yyyy, @Year - 1900, 0));

    DECLARE @endDate date = DATEADD(d, -1, DATEADD(m, @Month, DATEADD(yyyy, @Year - 1900, 0)));

    And then remove the converts in the where clause, you will get the same results and it will not only perform better - but be much easier to maintain.

    Also, since you are on 2008 and using the DATE data type - you can use BETWEEN since your date parameters are from the beginning of the month to the end of the month. Or, you could change to using greater than or equal and less than and remove the @endDate parameter:

    DECLARE @startDate date = dateadd(month, @month - 1, dateadd(year, @year - 1900, 0));

    SELECT ...

    FROM ...

    WHERE s.vtrRespDate >= @startDate

    AND s.vtrRespDate < dateadd(month, 1, @startDate);

    And finally, if your colum 'vtrRespDate is not a DATE data type - then you can use the following instead and it should still use an index:

    DECLARE @startDate date = dateadd(month, @month - 1, dateadd(year, @year - 1900, 0));

    SELECT ...

    FROM ...

    WHERE cast(s.vtrRespDate As date) >= @startDate

    AND cast(s.vtrRespDate As date) < dateadd(month, 1, @startDate);

    Jeffrey Williams
    “We are all faced with a series of great opportunities brilliantly disguised as impossible situations.”

    ― Charles R. Swindoll

    How to post questions to get better answers faster
    Managing Transaction Logs

Viewing 14 posts - 1 through 13 (of 13 total)

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