Select phone numbers depending on priority

  • Hello All,

    I have a table of staff members with a home, cell, and alternate phone numbers. Each phone number is assigned a priority of 1, 2, or 3.

    I want to produce a result set that will present the phone numbers based on that priority as well as a description of what kind of number each one is.

    I believe the sample data and desired results below should adequately explain the problem.

    Thanks to any one who can help.

    CREATE TABLE Staff

    (

    StaffID INT,

    Home [varchar](10) NULL,

    HomePriority [int] NOT NULL,

    Cell [varchar](10) NULL,

    CellPriority [int] NOT NULL,

    Alternate [varchar](10) NULL,

    AlternatePriority [int] NOT NULL

    )

    INSERT INTO Staff

    SELECT 1, '1111234561',1,'2222345672',2,'3339876543',3 UNION

    SELECT 2, '2221234523',2,'3332345665',3,'1119876597',1 UNION

    SELECT 3, '3331234511',3,'2222345625',2,'1119876587',1 UNION

    SELECT 4, '2221234531',2,'1112345635',1,'3339876576',3

    --Desired Results

    --StaffID,Phone1,Phone1Type,Phone2,Phone2Type,Phone3,Phone3Type

    --1,1111234561,Home,2222345672,Cell,3339876543,Alternate

    --2,1119876597,Alternate,2221234523,Home,3332345665,Cell

    --3,1119876587,Alternate,2222345625,Cell,3331234511.Home

    --4,1112345635,Cell,2221234531,Home,3339876576,Alternate

    SELECT * FROM Staff

  • You get an A+ for setting up the problem so perfectly. Thank you so much!! 😀

    Here's a solution for you

    select StaffID

    ,COALESCE(case when homepriority = 1 then home else null end

    ,case when cellpriority = 1 then cell else null end

    ,case when alternatepriority = 1 then alternate else null end

    ) as phone1

    ,COALESCE(case when homepriority = 1 then 'Home' else null end

    ,case when cellpriority = 1 then 'Cell' else null end

    ,case when alternatepriority = 1 then 'Alternate' else null end

    ) as phone1type

    ,COALESCE(case when homepriority = 2 then home else null end

    ,case when cellpriority = 2 then cell else null end

    ,case when alternatepriority = 2 then alternate else null end

    ) as phone2

    ,COALESCE(case when homepriority = 2 then 'Home' else null end

    ,case when cellpriority = 2 then 'Cell' else null end

    ,case when alternatepriority = 2 then 'Alternate' else null end

    ) as phone2type

    ,COALESCE(case when homepriority = 3 then home else null end

    ,case when cellpriority = 3 then cell else null end

    ,case when alternatepriority = 3 then alternate else null end

    ) as phone3

    ,COALESCE(case when homepriority = 3 then 'Home' else null end

    ,case when cellpriority = 3 then 'Cell' else null end

    ,case when alternatepriority = 3 then 'Alternate' else null end

    ) as phone3type

    from Staff

    __________________________________________________

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

  • We cannot always alter the existing schema. However, we can mimic 1NF with code!

    This is a simplified query

    SELECTs.StaffID,

    MAX(CASE WHEN f.Priority = 1 THEN f.Number ELSE '' END) AS Phone1,

    MAX(CASE WHEN f.Priority = 1 THEN f.Type ELSE '' END ) AS Phone1Type,

    MAX(CASE WHEN f.Priority = 2 THEN f.Number ELSE '' END ) AS Phone2,

    MAX(CASE WHEN f.Priority = 2 THEN f.Type ELSE '' END ) AS Phone2Type,

    MAX(CASE WHEN f.Priority = 3 THEN f.Number ELSE '' END ) AS Phone3,

    MAX(CASE WHEN f.Priority = 3 THEN f.Type ELSE '' END ) AS Phone3Type

    FROMdbo.Staff AS s

    CROSS APPLY(

    VALUES('Home', HomePriority, Home),

    ('Cell', CellPriority, Cell),

    ('Alternate', AlternatePriority, Alternate)

    ) AS f(Type, Priority, Number)

    GROUP BYs.StaffID


    N 56°04'39.16"
    E 12°55'05.25"

  • CELKO (7/21/2011)


    >> We cannot always alter the existing schema. <<

    I have started asking if this is possible in my standard "cut & paste" asking for minimal Netiquette. My experience for the last few decades is that bad DDL like this is the source of 80% or more of the DML problems and more than 90% of the performance problems when the system grows.

    I absolutely agree with THAT! Bad design not only causes performance problems, but it limits flexibility (can't add a "work" phone or 2nd alternate to the current design without a table change).

    The problem is that of 3rd party vendors (or, sometimes the "enemy" is within), many of which should be driven out of business for their simple ineptitude when it comes to decent table design. Yes, I agree... people should review their design before buying their product, but we all know how that works out.

    So, yeah... good question to ask in a standard cut'n'paste reply header.

    --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)
    Intro to Tally Tables and Functions

  • My schema design is not vendor-provided, legacy, already-in-production, it simply is ...bad design.

    Joe: thank you for pointing this out. I am now fixing the design.

  • Chrissy,

    Please note that the query using the revised design provides output in this format

    Staff_ID Phone_nbr

    1 1111234561

    2 1119876597

    3 1119876587

    4 1112345635

    Edited to add:

    Here is a query to get the desired results you requested from the new table design.

    SELECT s.Staff_ID,

    MAX(CASE WHEN s.phone_priority = 1 THEN s.phone_nbr ELSE '' END) AS Phone1,

    MAX(CASE WHEN s.phone_priority= 1 THEN s.phone_type ELSE '' END ) AS Phone1Type,

    MAX(CASE WHEN s.phone_priority = 2 THEN s.phone_nbr ELSE '' END ) AS Phone2,

    MAX(CASE WHEN s.phone_priority = 2 THEN s.phone_type ELSE '' END ) AS Phone2Type,

    MAX(CASE WHEN s.phone_priority = 3 THEN s.phone_nbr ELSE '' END ) AS Phone3,

    MAX(CASE WHEN s.phone_priority = 3 THEN s.phone_type ELSE '' END ) AS Phone3Type

    FROM Staff_Phones s

    group by staff_ID

    order by staff_ID

    __________________________________________________

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

  • Thank you. My database structure has been fixed and the additional code you provided is working. The non-normalized structure I need to output to is necessary to satisfy the requirement of a third party.

  • You can always create a denormalised view to satisfy the third-party application.

    But always keep the data normalised in the database.

    There is a big differense between storing the data, and enabling the data.


    N 56°04'39.16"
    E 12°55'05.25"

  • "You can always create a denormalised view to satisfy the third-party application.

    But always keep the data normalised in the database."

    "There is a big differense between storing the data, and enabling the data."

    Very well stated. This is a concept that is rarely understood and thus feared by far too many people with design decision making powers they should not have.

    The probability of survival is inversely proportional to the angle of arrival.

  • Thank you.

    On the other hand, if all people did this I would be out of work 🙂


    N 56°04'39.16"
    E 12°55'05.25"

  • " Select StaffID,'Phone1'=

    (case when HomePriority=1 then home

    when CellPriority=1 then Cell

    when AlternatePriority=1 then Alternate else null end),

    'Phone1Type'=(case when HomePriority=1 then 'home'

    when CellPriority=1 then 'cell'

    when AlternatePriority=1 then 'Alternate' else null end),

    'Phone2'= (case when HomePriority=2 then home

    when CellPriority=2 then Cell

    when AlternatePriority=2 then Alternate else null end),

    'Phone2Type'= (case when HomePriority=2 then 'home'

    when CellPriority=2 then 'cell'

    when AlternatePriority=2 then 'Alternate' else null end),

    'Phone3'=(case when HomePriority=3 then home

    when CellPriority=3 then cell

    when AlternatePriority=3 then Alternate else null end),

    'Phone3Type'=(case when HomePriority=3 then 'home'

    when CellPriority=3 then 'cell'

    when AlternatePriority=3 then 'Alternate' else null end)

    from Staff "

    sorry for posting a reply for such an old thread, I am sql server newbie recently starting to learn the ropes of Sql querying.I have found working on all the questions in the forums and old threads helpful and have been posting solutions on the threads.If anyone thinks i need to have a better querying approach,please feel free to correct me.:-)

  • manoj0134 (12/30/2011)


    sorry for posting a reply for such an old thread, I am sql server newbie recently starting to learn the ropes of Sql querying.I have found working on all the questions in the forums and old threads helpful and have been posting solutions on the threads.If anyone thinks i need to have a better querying approach,please feel free to correct me.:-)

    Absolutely nothing wrong with that! It's a time honored way of learning especially when someone takes the time to reply with suggestions! Welcome aboard!

    Just a couple of quick notes...

    First, nicely done on handling the denormalized data. Although the code can sometimes be a bit longer, they're frequently much faster than using a classic GROUP BY style of Cross Tabbing. The underlying problem with all of that is that usually means the table isn't properly normalized and won't suffer changes in requirements very easily.

    Shifting gears, I also use the columnname = expression method... it makes for some pretty easy to read code. However (and I'd have to look for the MS document), the 'columnname' = expression method (notice the single quotes there, the use of single quotes is what has been deprecated) has been deprecated and should be avoided for new code and, perhaps, be repaired whenever encounted in old code when a modification is required for other reasons. Of course, spaces and other characters that require quoted identifiers should be generally avoided but, if such characters are necessary, then you should encapsulate the column name in brackets rather than single quotes.

    Last but not least, consider a strong "vertical alignment" convention to make the code even more easy to read. Using your "casing" convention (my convention is quite different), here's how I would write the code...

    Select StaffID,

    Phone1 =

    case

    when HomePriority = 1 then Home

    when CellPriority = 1 then Cell

    when AlternatePriority = 1 then Alternate

    else null

    end,

    Phone1Type =

    case

    when HomePriority = 1 then 'Home'

    when CellPriority = 1 then 'Cell'

    when AlternatePriority = 1 then 'Alternate'

    else null

    end,

    Phone2 =

    case

    when HomePriority = 2 then Home

    when CellPriority = 2 then Cell

    when AlternatePriority = 2 then Alternate

    else null

    end,

    Phone2Type =

    case

    when HomePriority = 2 then 'Home'

    when CellPriority = 2 then 'Cell'

    when AlternatePriority = 2 then 'Alternate'

    else null

    end,

    Phone3 =

    case

    when HomePriority = 3 then Home

    when CellPriority = 3 then Cell

    when AlternatePriority = 3 then Alternate

    else null

    end,

    Phone3Type =

    case

    when HomePriority = 3 then 'Home'

    when CellPriority = 3 then 'Cell'

    when AlternatePriority = 3 then 'Alternate'

    else null

    end,

    from dbo.Staff

    ;

    Such "vertical alignment" makes it very easy to see that each pair of columns has been handled in an identical fashion which would also make it super easy for someone to add another column should the need ever arise.

    I also use the 2 part naming convention for all tables except Temp Tables to try to get folks into the habit of that "best practice".

    To include code on a post in one of those nice little colorized windows, simply include the code inbetween the appropriate "IFCode Shortcuts" that you will see to the left of the edit window when you're building your post. I recommend converting TABs to spaces to make you're life a bit easier as what you paste into the shortcut will be pretty much duplicated from what you see in SSMS (although it's not perfect).

    Last but not least, the "shape" of this post changed as it progressed. It was pointed out that the original form of the table was denormalized and should probably be normalized, instead. The next logical step would be for you to change the example table to a normalized form and then write code against that (or use the example code already posted).

    --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)
    Intro to Tally Tables and Functions

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

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