T-Sql rant

  • Selfless plug -- One of the articles now referenced in my signature block is actually mine, though it is based off Jeff's work.

  • Fox, I can't speak to Oracle. I'm totally ignorant there, although I'm told they code totally differently. I will say that, in SQL Server, solid set-based solutions almost always run faster than cursors and while loops. I say almost because it is possible to have BAD set based solutions that grind slow. One day you may hear about triangular joins and RBAR, but trust me you don't want to go there yet.

    There comes a point where performance gains come from examining the execution plans of queries, the table structure constraints and indices, the locking that's going on in the system, and probably a lot of other stuff I can't think of right now. The answers aren't always to be found in 20 lines code, but as you convert over from cursors, your code on SQL Server is going to run much faster.

    __________________________________________________

    Against stupidity the gods themselves contend in vain. -- Friedrich Schiller
    Stop, children, what's that sound? Everybody look what's going down. -- Stephen Stills

  • let's say we have the table with

    partnumber, producttype, sequence

    After inserting part in the table we need to resequence the sequence number which depends on the partnumber.

    so select partnumber from tbl order by partnumber -- assumming 10 records the sequence should be

    1 to 10.

    When inserting a part (lets say we insert many parts, with differing producttypes. We would then have to resequence each producttype set after the inserts (or deletes) have been done.

    so if we say select * from partnumber, producttype orderby producttype, partnumber

    the sequence would begin at 1 and end at the end for each producttype in the table.

    Now you know I am going to ask how would you resequence the parts (without updating the already sequenced records or correctly sequenced records)

    Meaning if we have 1,2,3,4,5,6 and we enter a record at pos 4, we don't need to update the records that contain the sequence of 1,2,3.

  • foxjazz (3/18/2009)


    {} is much better than BEGIN BEGIN BEGIN BEGIN END END END END

    For you, perhaps. I find BEGIN END just fine. Remember I did come from a development environment where we actually used COBOL. You think T-SQL is wordy?

    Any way, I'd never write either {{{{}}}} or BEGIN BEGIN BEGIN BEGIN END END END END. it would look like this:

    BEGIN

    BEGIN

    BEGIN

    BEGIN

    END

    END

    END

    END

    or, using {}:

    {

    {

    {

    {

    }

    {

    {

    {

    I like white space. It makes thing more readable.

  • foxjazz (3/18/2009)


    {} is much better than BEGIN BEGIN BEGIN BEGIN END END END END

    Heh quite possibly - but the count of BEGIN - END pairs goes right down once people realise that they're waaaaaay overused.

    The BEGIN and END are not needed here because the IF is followed by a single statement:

    IF OBJECT_ID('tempdb..#Temp') IS NOT NULL

    BEGIN

    DROP TABLE #Temp

    END

    Many people wrap their entire stored procedure within a BEGIN - END block - why?

    The main culprit of course is loops. Once you start thinking set-based, the count of BEGIN - END pairs in your code will go right down and you will wonder what all the fuss was about.

    “Write the query the simplest way. If through testing it becomes clear that the performance is inadequate, consider alternative query forms.” - Gail Shaw

    For fast, accurate and documented assistance in answering your questions, please read this article.
    Understanding and using APPLY, (I) and (II) Paul White
    Hidden RBAR: Triangular Joins / The "Numbers" or "Tally" Table: What it is and how it replaces a loop Jeff Moden

  • foxjazz (3/18/2009)


    let's say we have the table with

    partnumber, producttype, sequence

    After inserting part in the table we need to resequence the sequence number which depends on the partnumber.

    so select partnumber from tbl order by partnumber -- assumming 10 records the sequence should be

    1 to 10.

    When inserting a part (lets say we insert many parts, with differing producttypes. We would then have to resequence each producttype set after the inserts (or deletes) have been done.

    so if we say select * from partnumber, producttype orderby producttype, partnumber

    the sequence would begin at 1 and end at the end for each producttype in the table.

    Now you know I am going to ask how would you resequence the parts (without updating the already sequenced records or correctly sequenced records)

    Meaning if we have 1,2,3,4,5,6 and we enter a record at pos 4, we don't need to update the records that contain the sequence of 1,2,3.

    I'll be honest, for me trying to work just off your word description of a problem is difficult. It would help if you provided an actual example of what you are trying to accomplish here. One of my favorite sayings is "Pretend I'm from Missouri, and show me what you want". By the way, Missouri is also known as the Show Me State. I am much more of a visual person, which is why I DON'T do telephone technical support.

  • Chris Morris (3/18/2009)


    foxjazz (3/18/2009)


    {} is much better than BEGIN BEGIN BEGIN BEGIN END END END END

    Heh quite possibly - but the count of BEGIN - END pairs goes right down once people realise that they're waaaaaay overused.

    The BEGIN and END are not needed here because the IF is followed by a single statement:

    IF OBJECT_ID('tempdb..#Temp') IS NOT NULL

    BEGIN

    DROP TABLE #Temp

    END

    Many people wrap their entire stored procedure within a BEGIN - END block - why?

    The main culprit of course is loops. Once you start thinking set-based, the count of BEGIN - END pairs in your code will go right down and you will wonder what all the fuss was about.

    I wrap my entire store procedures in a BEGIN END block, why? It clearly delineates the stored procedure for one. Also, somewhere in another thread, I think Jeff Moden actually found a slight performance gain be doing it as he never did it either. This is something that probably should be investigated in more depth in a different thread.

  • Lynn Pettis (3/18/2009)


    foxjazz (3/18/2009)


    {} is much better than BEGIN BEGIN BEGIN BEGIN END END END END

    For you, perhaps. I find BEGIN END just fine. Remember I did come from a development environment where we actually used COBOL. You think T-SQL is wordy?

    Any way, I'd never write either {{{{}}}} or BEGIN BEGIN BEGIN BEGIN END END END END. it would look like this:

    BEGIN

    BEGIN

    BEGIN

    BEGIN

    END

    END

    END

    END

    or, using {}:

    {

    {

    {

    {

    }

    {

    {

    {

    I like white space. It makes thing more readable.

    Lynn,

    What I found usefull and now we have it in our coding standards si to use comments with each BEGIN and END to make it easier to read so the code would look like this. I think code readability is a very important factor too often overlooked.

    BEGIN --MailChecks

    BEGIN --BuyMilk

    BEGIN --RakeTheGarden

    BEGIN --PaintTheHouse

    END --PaintTheHouse

    END --RakeTheGarden

    END --BuyMilk

    END --MailChecks

    ---------------------------------------------
    [font="Verdana"]Nothing is impossible.
    It is just a matter of time and money.[/font]

  • After inserting part in the table we need to resequence the sequence number which depends on the partnumber

    '

    Fox, I will write a little bit of code to do it. But first I'm going to say that part of relational db thinking is that a sequence number that depends on the part number is totally unnecessary for what we do. We can sequence based on the part numbers themselves, we may even build a totally different index to support that. If we want to add a row, we just add it and use ORDER BY on the column itself, not on a sequence number.

    Look at the results from the two queries at the bottom. They are identical. Since I know I don't have to do a loop to "read a row, increment a sequence number by 1, then read another row", I can disregard the sequence number entirely. It adds no functionality I didn't already have. This is important, because I'm trying to get you to see how we THINK about problems differently. It's good practice to always make sure each row has a unique key, but we order by whatever is convenient for the report or application at hand.

    create table #parts (partnumber varchar(10), productType varchar(10), sequence int)

    insert into #parts

    select 'A23455','Carburetor', 1 union all

    select 'A23456','Carburetor', 2 union all

    select 'B23454','Carburetor', 3

    select partnumber,productType from #parts

    order by PARTNUMBER

    select partnumber,productType from #parts

    order by SEQUENCE

    drop table #parts

    Also, please observe how I've set up the problem. I give you (and everyone else) the code to create a table, and some data to illustrate. Anyone can cut and paste this, to test it, or to change it. If you say you are looking for certain results, we can be sure our solution delivers before we post.

    I know you are experiencing technical difficulties with your hardware, but when they are resolved you will find that taking ten minutes to set up the problem gets you solid answers MUCH quicker.... and you may even realize what the problem is yourself while setting up the question.

    __________________________________________________

    Against stupidity the gods themselves contend in vain. -- Friedrich Schiller
    Stop, children, what's that sound? Everybody look what's going down. -- Stephen Stills

  • let me give some data

    partnumber, producttype, sequence

    7401,belt,1

    7432,belt,2

    8401,hose,1

    8422,hose,2

    This is the table.

    inert a record (8403,hose,?)

    after a resequence you would have

    8401,hose,1

    8402,hose,2

    8422,hose,3

  • Now you know I am going to ask how would you resequence the parts (without updating the already sequenced records or correctly sequenced records)

    Well, I have seen a case where the prefix of a part number was used to identify the supplier. Since that part number was communicated to repeat customers, the scheme began to fall apart when a better supplier was found. You just could not change a part number like that.

    In the same vein, the UPC code was abused to enter the product part number - it just limited you the first 6 digits, and only if you had no letters in the part number. Since you could not change a released UPC code either, this resulted in gaps in the sequence numbers.

    In your case, I do not understand why you would want to "resequence" the table. Its primary key is only intended to allow the server to distinguish between identical records yes, I know, this violates 3NF - and all the children will go home in time for supper - right!). And if you want to change a primary key, then this screws up the foreign keys in the detail tables.

    The actual sequence of records in a database is not relevant. If you are concerned with ordering, you will be better served with the ORDER BY clause.

  • OK DAMN

    I don't have it all wrong, but here is the issue.

    The user defines the sequence, it isn't alphabetical. So when inserting a record the user would give 2 as the sequence, and the rest of the records have to be re-sequenced.

  • foxjazz (3/18/2009)


    let me give some data

    partnumber, producttype, sequence

    7401,belt,1

    7432,belt,2

    8401,hose,1

    8422,hose,2

    This is the table.

    inert a record (8403,hose,?)

    after a resequence you would have

    8401,hose,1

    8402,hose,2

    8422,hose,3

    Before I write any code, plus I have work to do here so it will have to wait for lunch time, it appears that the actual sequence is the Part Number, correct?

    With that, here is something else you should start to understand. There is no order to how data is stored in a Relational Database. Not totally true, as if you have a clustere index defined, the data is stored in the order of the clustered index. Order in a relational database is dtermined by the ORDER BY clause when selecting data.

  • Continuing my previous example with your data. I get the results desired by simply ignoring the sequence number column. If I'm going to do this a lot, I will be sure to have one or more indexes that are primarily based on partnumber.

    If I don't insist that there MUST be a sequence number, there is no problem to begin with.

    create table #parts (partnumber varchar(10), productType varchar(10), sequence int)

    insert into #parts

    select 7401,'belt',1 union all

    select 7432,'belt',2 union all

    select 8401,'hose',1 union all

    select 8422,'hose',2

    select partnumber,productType from #parts

    order by PARTNUMBER

    insert into #parts

    select 8403,'hose',0

    select partnumber,productType from #parts

    order by PARTNUMBER

    drop table #parts

    __________________________________________________

    Against stupidity the gods themselves contend in vain. -- Friedrich Schiller
    Stop, children, what's that sound? Everybody look what's going down. -- Stephen Stills

  • foxjazz (3/18/2009)


    It seems that if I write a query like this:

    declare @i int

    select top 10 @i = @i + 1 , partnumber from prd

    I shouldn't get an error. But hell what do I know.

    The problem is that you are mixing 2 uses of SELECT.

    SELECT @i=@i+1

    SELECT @x=col FROM tbl

    Both these are assigning values. In the second case, if multiple rows are returned, then the 'last' value gets assign, so if you haven't used ORDER BY then anything may happen. The form SELECT @x=@x+col FROM tbl is only really used for concatenation. To produce a total SUM(col) would be more efficient

    SELECT col FROM tbl

    This actual returns a table which may be used by an outer query of returned to a calling application. In the case where the calling application is Query Analyzer or Management Studio, then application simply displays the table.

    I assume that your query

    select top 5 @i=@i+1, partnumber from prd

    is trying to get a list of partnumber with a sequence.

    Since tables are (theoretically) unordered, this is meaningless unless you apply an ordering.

    I've already shown one way to do this

    -- you can omit the 'top 5' from either select to get the same result

    create table #i (i int identity(1,1), partnumber int)

    insert #i (partnumber)

    select top 5 partnumber from prd

    select top 5 i,partnumber from #i

    drop table #i

    An alternative, not using temp tables or IDENTITY is to use a self join.

    select top 5 count(*) as 'i', a.partnumber from prd a, prd b

    where a.partnumber >= b.partnumber

    group by a.partnumber

    order by a.partnumber

    These won't actually produce the same result, since the first will return the partnumbers in whatever order they happen to be in tabel prd, while the second returns them in partnumber order.

    There are probably more efficient ways to do this. Since I use SS2K5, I'd probably just use row_number(), so I'm having to think a bit about what SS2K can do! 🙂

    Derek

Viewing 15 posts - 241 through 255 (of 465 total)

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