row_number() help!

  • I have a searching SP that uses the row_number() function to help out with paging. But for some weird reason Im getting duplicate results when I run the query. But if I take out the row_number() funciton I get normal results. Here is what I have got, please help me with getting this solved, im tearing my hair out!

    WITH SearchTable AS

    (

    select distinct

    st.id,

    st.title,

    st.sub_title,

    st.synopsis,

    st.short_code,

    ROW_NUMBER() OVER (ORDER BY st.title asc) AS RowNumber

    from stock as st left join

    Keywords on Keywords.stock_id = st.id left join

    OnlinePreviews opLow ON opLow.stock_id = st.id and opLow.[type] = 1 left join

    OnlinePreviews opHigh ON opHigh.stock_id = st.id and opHigh.[type] = 2 left join

    TeachersNotes tn ON tn.stock_id = st.id inner join

    Stock_Subjects ss ON ss.stock_id = st.id inner join

    Subjects sub ON sub.id = ss.subject_id

    )

    select

    id,

    title,

    sub_title,

    synopsis,

    short_code,

    RowNumber

    from SearchTable st

    Where

    RowNumber between ((@page - 1) * @results) AND (@page * @results)

    Order by short_code

    So thats the SQL, but keep in mind the entire SQL works fine if we take all all references to the row_number() function. If I leave the row_function() in then I can work out that it is my inner joins thats the problem, if I slowly remove the inner joins and keep in the row_number(), I figured out that the joins on the Stock_Subjects table is the problem.

    Why would this give different results when I use the row_number() funciton?

    Thanks heaps to who ever solves this, I just can't figure it out!

  • The problem I guess is that the table Stock_Subjects has many to 1 relation to the table Stock.

    Since you are not using any columns from that table, you can take the join out of the FROM clause and use a WHERE EXISTS(SELECT 1 FROM Stock_Subjects ss WHERE ss.stock_id = st.id)

    E.g.:

    WITH SearchTable AS

    (

    select distinct

    st.id,

    st.title,

    st.sub_title,

    st.synopsis,

    st.short_code,

    ROW_NUMBER() OVER (ORDER BY st.title asc) AS RowNumber

    from stock as st left join

    Keywords on Keywords.stock_id = st.id left join

    OnlinePreviews opLow ON opLow.stock_id = st.id and opLow.[type] = 1 left join

    OnlinePreviews opHigh ON opHigh.stock_id = st.id and opHigh.[type] = 2 left join

    TeachersNotes tn ON tn.stock_id = st.id inner join

    Subjects sub ON sub.id = ss.subject_id

    WHERE EXISTS(SELECT 1 FROM Stock_Subjects ss WHERE ss.stock_id = st.id)

    )

    select

    id,

    title,

    sub_title,

    synopsis,

    short_code,

    RowNumber

    from SearchTable st

    Where

    RowNumber between ((@page - 1) * @results) AND (@page * @results)

    Order by short_code

  • Will that Exists function slow down the query at all?

    I mean, in terms of the performance of that function in comparison to a join.

    Also it seems that when I use that Exists() function I can no longer join to the subjects table which is joined to the stock_subjects. Is there any way I can join to a table inside the Exists() function?

  • Well maybe I can go about doing this another way, the issue here is that when a user passes a comman seperated list of subject id's to my SP, i need to return all stock items that relate to any of the id's in that comma seperated list.

    This is what I have so far (shortened)

    select distinct

    st.id,

    st.title,

    st.sub_title,

    st.synopsis,

    ROW_NUMBER() OVER (ORDER BY st.title asc) AS RowNumber

    from stock as st left join

    Keywords on Keywords.stock_id = st.id left join

    Stock_Subjects ss ON ss.stock_id = st.id inner join

    Subjects sub ON sub.id = ss.subject_id

    Where

    --Subject, if specified, list onlu stock items for given subject id

    (

    @subject_list = '0'

    OR

    (dbo.IsInCommaList(@subject_list, sub.id) = 1 AND sub.parent_subject_id is null)

    )

    AND

    --Sub-subject, if specified, list onlu stock items for given sub_subject id

    (

    @sub_subject_id = 0

    OR

    (sub.id = @sub_subject_id AND sub.parent_subject_id is not null)

    )

    Note: dbo.IsInCommaList just checks to see if the given subject id is in the comma seperated list, this works fine, but I cant use it because of the issue with the joins.

    Can anyone think of a better way of doing this?

  • >>Can anyone think of a better way of ...

    >>dbo.IsInCommaList(@subject_list, sub.id) = 1

    >>works fine, but I cant use it because of the issue with the joins.

    Not sure if this is a "better" way but I just had a similar requirement (item in comma-separated list) and I *was* able to solve it with a join.  It looked something like this:

    set @subject_list = ',' + @subject_list + ','
    -- make sure starting and ending delimiters are in place
    -- then set your join to something like this (not sure
    -- I've got exactly what you need here):
    INNER JOIN Subjects sub ON sub.id = ss.subject_id AND
     PATINDEX ( ',%' + sub.id + '%,' ,@subject_list ) > 0 
    

    Note: if your comma-delimited list has potential extra spaces around each item that need to be removed (or something like that) you can take care of that sort of thing with some additional manipulation of the @subject_list variable before doing the join.  Tedious, but not impossible.

    [Please don't everybody tell me I should have changed the incoming information so I didn't have to do this... it wasn't an option.  And it actually does work with reasonable speed, considering all the other factors in the scenario...]

    >L<

  • Followup thought: I think in your situation you don't need the '%' wildcards in the PATINDEX expression, just the embracing commas.

    Sorry if that was confusion/red herring.

    >L<

  • Actually, PatIndex does need the wildcards as it performs a pattern search much like the keyword LIKE. Without the wildcards, the entire strings would have to be exact matches. You can leave out the wildcards if you use CharIndex instead of PatIndex.

    The reason that the distinct doesn't work is because row_number() makes each row unique as each row has a different row_number.


    My blog: SQL Soldier[/url]
    SQL Server Best Practices:
    SQL Server Best Practices
    Twitter: @SQLSoldier
    My book: Pro SQL Server 2008 Mirroring[/url]
    Microsoft Certified Master: SQL Server, Data Platform MVP
    Database Engineer at BlueMountain Capital Management[/url]

  • >>

    Actually, PatIndex does need the wildcards as it performs a pattern search much like the keyword LIKE. Without the wildcards, the entire strings would have to be exact matches. You can leave out the wildcards if you use CharIndex instead of PatIndex.

    <<

    That's what I meant: he *can* use charindex instead of patindex in his situation, I bet.   In my situation the strings within the delimited set could actually be partials, so the %'s and patindex are necessary... but it was muddying the waters to suggest that for his scenario, as I had originally done.

    The point is that he has a delimited string in which he has to find a string, and that this approach *can* be used in a join expression.  Which is what he wants to do, and which he apparently thought he couldn't do. 

    >>The reason that the distinct doesn't work

    I have no idea what you're after regarding DISTINCT, that must be in response to something else in the thread.  At least, I hope I didn't say anything about DISTINCT; I certainly didn't meant to, AAR!

    >L<

     

  • No, you didn't say distinct, but it is in his original query and is useless when you add something like row_number to the select list.


    My blog: SQL Soldier[/url]
    SQL Server Best Practices:
    SQL Server Best Practices
    Twitter: @SQLSoldier
    My book: Pro SQL Server 2008 Mirroring[/url]
    Microsoft Certified Master: SQL Server, Data Platform MVP
    Database Engineer at BlueMountain Capital Management[/url]

  • Exactly! which was the problem, so I found that the joins were the issue here, and I needed to re-think the way my query was to work.

  • >>so I found that the joins were the issue here, and I needed to re-think the way my query was to work.

    OIC, sorry, then can you use PeterHe's EXISTS suggestion and bring the subjects condition in as you need to?

    I see that you have suggested this, but I'm not sure what the problem is. 

    IOW, something like what I've cribbed together below using what he demonstrated *should* work for you (I'll use the CHARINDEX thing that seems appropriate for your comma-delimited set of subjects, with caveats as before that this might not be exactly the syntax you need for your conditions but that the UDF isn't necessary). 

    I don't have your data set but it seems to do the trick for me with similar one-to-many relationships...

    SET @Subject_list = ',' + @Subject_list + ','

    WITH SearchTable AS
    (
    select distinct
    st.id,
    st.title,
    st.sub_title,
    st.synopsis,
    st.short_code,
    ROW_NUMBER() OVER (ORDER BY st.title asc) AS RowNumber
    
    from stock as st left join 
    Keywords on Keywords.stock_id = st.id left join
    OnlinePreviews opLow ON opLow.stock_id = st.id and opLow.[type] = 1 left join
    OnlinePreviews opHigh ON opHigh.stock_id = st.id and opHigh.[type] = 2 left join
    TeachersNotes tn ON tn.stock_id = st.id 
    
    WHERE EXISTS(SELECT 1 FROM Stock_Subjects ss 
                 INNER JOIN Subjects sub ON 
                 ss.subject_id = sub.id AND 
                 CHARINDEX(sub.id,@subject_list) > 0
                 WHERE ss.stock_id = st.id)
    )
    

    ... ?

    I know you said "Also it seems that when I use that Exists() function I can no longer join to the subjects table which is joined to the stock_subjects. Is there any way I can join to a table inside the Exists() function?"... but I'm not seeing the problem with doing this. 

    I apologize if I am misunderstanding something...

    >L<

     

Viewing 11 posts - 1 through 10 (of 10 total)

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