Adding either a "1" or "2" in a column (using Select, Union All, and three tables)

  • Thanks for reading the post... I just registered today because my search of the site is not giving me the result I was hoping for.

    I have a stored proc pulling data from three tables. The results are being formatted for display on first a web site and maybe a tablet\mobile app later. The desired result of the query would return the following data

    1 Customer 1

    1 Open 15

    1 Closed 50

    1 New 10

    2 Customer 2

    2 Open 25

    2 Closed 550

    2 New 122

    1 Customer 3

    1 Open 89

    1 Closed 231

    1 New 1

    I would like to have the first column be a one or a two for each group but I have no idea how to do it.

    I am working with three tables

    Customers

    Cust_Key

    Customer_Name

    Orders

    Order_Key

    Cust_Key

    Status Key

    Status_LookUp

    Status_Key

    Status_text

    I am building the output using two SQL commands joined with a Union All. What I want to do now is to have either a 1 or a 2 in the first column so I can tell the GirdView object in VS2010 to change colors of the rows for each grouping.

    The current data being outputted is --

    Column 1 - Customer Name

    Column 2 - Distinct Status (there could be 4, or 10)

    Column 3 - The count of the orders with the status, by customer

    Here is the T-SQL that I am using.

    Declare @Customer_Orders as table

    (

    Sort int,

    Customer_Key int,

    Customer_Name VarChar(75),

    Status_text VarChar(15),

    Order_Count VarChar(15)

    )

    Insert into @Customer_Orders

    Select

    c.Cust_Key * 100,

    c.Cust_Key,

    C.Customer_Name,

    '',

    ''

    From Customer C

    Union All

    Select

    O.Cust_Key * 100 + 10 as Sort,

    O.Cust_Key,

    '',

    S.status_text,

    cast(COUNT(o.Order_Key) as VarChar(15))

    From Orders O

    Join Status_LookUp S on O.Status_Key = S.status_key

    Group By O.Cust_Key, S.status_text

    Select Customer_Name as Customer, Status_text as Status, Order_Count as Quantity

    From @Customer_Orders

    Order By Sort, Customer

    If someone can at least give me an idea of what to look for it would be great. Or of you know of a better way to do it... I am all ears.

    Tim Sapp

  • Not information to check what wrong and what you require. You may want to read Jeff Moden's article on how to post your problems to get fast and accurate answers [/url]from other forum members.

  • Yeah I was typing away and hit the enter button and bang! the message was sent. You read it while I was "Editing" my post to add more details. πŸ˜€

    I hope I have given you enough details on what I need help with.

    Tim Sapp

  • TDSapp (10/4/2011)


    I hope I have given you enough details on what I need help with.

    You could give us the criteria for a customer being in group 1 or group 2... That would be helpful.

    In itself, adding a column to return 1 or 2 is easy:

    select case when criterium_here = 1 then 1 else 2 end as [group], ...

    edit: coming to think of it, do you intend to make the even rows show in a different color than the uneven rows? If so, what about this:

    select (row_number() over (order by (select 1)) % 2) as [group], ...

    Having your results returned in 4 rows per customer is a very bad design though. SQL should be used to return a row per customer and on this row all 3 figures for that customer should be returned. The front-end should then decide how to present the information: in your case, a line for the customer name plus 3 lines for the numbers. Think about what will happen if your application is asked to support 'landscape' overviews too: the end user no longer wants the numbers shown under the customer, but now they want them after the customer on the same line. Will you go and write another query for this landscape overview too?



    Posting Data Etiquette - Jeff Moden[/url]
    Posting Performance Based Questions - Gail Shaw[/url]
    Hidden RBAR - Jeff Moden[/url]
    Cross Tabs and Pivots - Jeff Moden[/url]
    Catch-all queries - Gail Shaw[/url]


    If you don't have time to do it right, when will you have time to do it over?

  • R.P.Rozema (10/5/2011)

    edit: coming to think of it, do you intend to make the even rows show in a different color than the uneven rows? If so, what about this:

    select (row_number() over (order by (select 1)) % 2) as [group], ...

    You are correct, this is what I was looking for....

    R.P.Rozema (10/5/2011)

    Having your results returned in 4 rows per customer is a very bad design though. SQL should be used to return a row per customer and on this row all 3 figures for that customer should be returned. The front-end should then decide how to present the information: in your case, a line for the customer name plus 3 lines for the numbers. Think about what will happen if your application is asked to support 'landscape' overviews too: the end user no longer wants the numbers shown under the customer, but now they want them after the customer on the same line. Will you go and write another query for this landscape overview too?

    I actually started thinking about this last night after I got home. For two reasons, one, I would be able to just set up the GridView object to auto-magically swap the row colors, and two, it would take less valuable screen landscape. While not an issue on a PC most of the time, it's a real issue on a tablet.

    I may have to look at it today and make a few changes.

    Tim

  • CELKO (10/5/2011)


    Please post DDL, so that people do not have to guess what the keys, constraints, Declarative Referential Integrity, data types, etc. in your schema are. Please learn to follow ISO-11179 data element naming conventions and formatting rules. Temporal data should use ISO-8601 formats. Code should be in Standard SQL as much as possible and not local dialect.

    Well, the naming and the table design was something that was done before I got here. We get to use what we are given... This is actually a database that is compiled from about 4 SQL Databases and a couple Access databases. We have to keep the names the same so we can manage what has to be updated and moved around for now. Maybe in the future we can change it to follow the standards, but for now, it is what it is.

    CELKO (10/5/2011)


    You got everything wrong. A status is a β€œ<something>_status” and it is an attribute not a table with a key. What is the key of the numeric constants pi? Yes, what you did is that kind of fundamental modeling error. Oh, data element name tell use what something is (identifier) and never how it is used in one table (_key)

    Kind of direct ain't ya.

    As for the status, that is from a look up table where the Primary Key of the table is the field being used in the Orders table. The end user can add a status as the system and the processes in the company change and flow. It keeps us from having to replicate the same text over and over not knowing what we are going to be needing in the future.

    CELKO (10/5/2011)


    If you want to learn how to ask a question on a Newsgroup, look at: http://www.catb.org/~esr/faqs/smart-questions.html

    Not a bad link, but I do like the like the one that ColdCoffee posted better (http://www.sqlservercentral.com/articles/Best+Practices/61537/ ) it is more relevant to this site.

    CELKO (10/5/2011)


    Here is a DDL skeleton to replace your narrative

    CREATE TABLE Customers

    (cust_id CHAR(15) NOT NULL PRIMARY KEY,

    cust_name VARCHAR(25) NOT NULL,

    ..);

    CREATE TABLE Orders

    (order_nbr CHAR(10) NOT NULL PRIMARY KEY,

    order_status CHAR(3) DEFAULT 'new' NOT NULL

    CHECK (order_status IN ('open', 'close', 'new')),

    ..);

    The SQL programming idiom for this kind of query is:

    SELECT C.cust_id, C.cust_name,

    SUM(CASE WHEN O.order_status = 'new'

    THEN 1 ELSE 0 END)

    AS new_tot,

    SUM(CASE WHEN order_status = 'close'

    THEN 1 ELSE 0 END)

    AS close_tot,

    SUM(CASE WHEN order_status = 'new'

    THEN 1 ELSE 0 END)

    AS open_tot

    FROM customers AS C, Orders AS O

    WHERE C.cust_id = O.cust_id

    GROUP BY C.cust_id, C.cust_name;

    Now pass this to the display layer and let it does its

    As I said in the post right before yours I am actually changing how I am going to out the data to the app. I am moving to a single row for each customer with one column containing the count of the orders for each status. What your code above does not take into consideration is having more than three status levels, and never knowing how many there will be in the future. I don't want to have to change a stored proc just every time someone adds a status.

    However, I am not sure how to do this step either. Since there can be any number of columns in the status table that means there can be any number of columns for each client. I don't mind if they have zeros in the fields if they don't have a status, but just knowing how to tie them all together is my next step.

    Here is a set of example tables and some sample data to work with. (Yes, I can read... πŸ™‚ )

    IF OBJECT_ID('TempDB..#Customer','U') IS NOT NULL

    DROP TABLE #Customer

    CREATE TABLE #Customer

    (Cust_Key int IDENTITY(1,1) NOT NULL PRIMARY KEY,

    Customer_Short_Name varchar(10) NULL,

    Customer_Name varchar(50) NULL)

    SET IDENTITY_INSERT #Customer ON

    Insert into #Customer

    (Cust_Key, Customer_Short_Name, Customer_Name)

    Select '1','Cust1','First Customer' Union ALL

    Select '2','Val','Valuable Customer' Union ALL

    Select '4','UTA','UT of Arlington' Union ALL

    Select '5','OU','Oklahoma University' Union ALL

    Select '6','GM','General Motors' Union ALL

    Select '7','VC','Virginia Chili'

    SET IDENTITY_INSERT #Customer OFF

    IF OBJECT_ID('TempDB..#Status_LookUp','U') IS NOT NULL

    DROP TABLE #Status_LookUp

    Go

    CREATE TABLE #Status_LookUp

    (status_key int IDENTITY(1,1) NOT NULL PRIMARY KEY,

    status_text varchar(50) NULL,

    status_type varchar(10) NULL)

    GO

    SET IDENTITY_INSERT #Status_LookUp ON

    Insert into #Status_LookUp

    (status_key, status_text, status_type)

    Select '1','Not Set','ALL' Union ALL

    Select '2','Open','ALL' Union ALL

    Select '3','Closed','ALL' Union ALL

    Select '4','New Order','Order' Union ALL

    Select '5','Shipped','ALL' Union ALL

    Select '6','Partial Shipped','Order' Union ALL

    Select '7','IN ERROR','ALL' Union ALL

    Select '8','At Press','LineItem'

    SET IDENTITY_INSERT #Status_LookUp OFF

    Go

    IF OBJECT_ID('TempDB..#Orders','U') IS NOT NULL

    DROP TABLE #Orders

    Go

    CREATE TABLE #Orders(

    Order_Key int IDENTITY(1,1) NOT NULL PRIMARY KEY,

    Fulfillment_Order_Key VarChar(50) NULL,

    Cust_Key int NULL,

    Order_Date date NOT NULL,

    Status_Key int DEFAULT ((1)) NOT NULL)

    Go

    SET IDENTITY_INSERT #Orders On

    Insert into #Orders

    (Order_Key, Fulfillment_Order_Key, Status_Key, Order_Date, Cust_Key)

    Select '7488','1000211273','1','2011-09-19','11' Union ALL

    Select '7489','1000211285','2','2011-09-19','6' Union ALL

    Select '7490','1000211278','4','2011-09-19','8' Union ALL

    Select '7491','1000211292','5','2011-09-19','6' Union ALL

    Select '7492','1000211276','6','2011-09-19','7' Union ALL

    Select '7493','1000211280','4','2011-09-19','11' Union ALL

    Select '7494','1000211279','2','2011-09-19','6' Union ALL

    Select '7495','1000211284','1','2011-09-19','7' Union ALL

    Select '7496','1000211274','4','2011-09-19','6' Union ALL

    Select '7497','1000211291','7','2011-09-19','8' Union ALL

    Select '7498','1000211286','3','2011-09-19','8' Union ALL

    Select '7499','1000211275','2','2011-09-19','11' Union ALL

    Select '7500','1000211287','6','2011-09-19','11' Union ALL

    Select '7501','1000211290','6','2011-09-19','7' Union ALL

    Select '7502','1000211282','7','2011-09-19','8' Union ALL

    Select '7503','1000211288','2','2011-09-19','11' Union ALL

    Select '7504','1000211289','1','2011-09-19','11' Union ALL

    Select '7505','1000211283','1','2011-09-19','6' Union ALL

    Select '7506','1000211281','5','2011-09-19','11' Union ALL

    Select '7507','1000211277','5','2011-09-19','6' Union ALL

    Select '7508','1000211312','6','2011-09-19','11' Union ALL

    Select '7509','1000211303','6','2011-09-19','8' Union ALL

    Select '7510','1000211297','6','2011-09-19','11' Union ALL

    Select '7511','1000211300','4','2011-09-19','6' Union ALL

    Select '7512','1000211294','3','2011-09-19','8' Union ALL

    Select '7513','1000211301','4','2011-09-19','8' Union ALL

    Select '7514','1000211296','2','2011-09-19','11' Union ALL

    Select '7515','1000211307','3','2011-09-19','8' Union ALL

    Select '7516','1000211306','6','2011-09-19','11' Union ALL

    Select '7517','1000211308','5','2011-09-19','6'

    SET IDENTITY_INSERT #Orders OFF

    What I would really like to do is return a table that has a customer column, and then one column for each status. The status column would be named after the status that the column contains.

    I guess I could start off with a temp table with just customer as a field and then run a loop to add columns to the table, one for each status.

    What a great day... trying to figure this out with a Sinus infection is not making my day fun.

    Tim

  • TDSapp (10/6/2011)


    CELKO (10/5/2011)


    What I would really like to do is return a table that has a customer column, and then one column for each status. The status column would be named after the status that the column contains.

    You need to use dynamic SQL to create this. Have a look at Jeff's article on Dynamic Cross Tabs http://www.sqlservercentral.com/articles/Crosstab/65048/

    What I have done in the past on the assumption that tables like this will be fairly stable, is create a trigger on the table that dynamically creates a view for the cross tab. That way, you don't have to create the cross tab query every time you want to access it.

    Drew

    J. Drew Allen
    Business Intelligence Analyst
    Philadelphia, PA

  • Ok, so let's assume you've got a trigger that creates the view dynamically. And thus you've got the view all set to return all totals for all statusses in a single row, how is your application going to know for which columns to query? I'd say you define which columns need to be shown in the overview and you create the query for that. At the time a new status is added that per the new requirements needs to be shown in the overview, you introduce a new version of your application/web site that knows to query for and show this new status. But wait, if you have to build a new version of the application/web site, then why would you not at that time build the new view too? I'm a bit over-dramatic here of course, but do you really want your application to blindly follow the statusses that an end-user enters into your lookup table? What if they start entering 10, 20 or even 100 statusses, will your screen be wide enough and do you really want to query for all customers all these statusses so they can be shown on each line? I'd say you go back to the person who wrote the specs and ask him/her for which statusses (s)he wants the overview to show the totals. Doing so avoids all the needed tricks that will eventually bite you in the foot. Wise men said: "Keep it simple" and even though I am not as wise, I say the same.

    Note: to get the totals on the single row together with the customer, you can indeed best use the crosstab technique described by Jeff Moden (a link is in my footer text).



    Posting Data Etiquette - Jeff Moden[/url]
    Posting Performance Based Questions - Gail Shaw[/url]
    Hidden RBAR - Jeff Moden[/url]
    Cross Tabs and Pivots - Jeff Moden[/url]
    Catch-all queries - Gail Shaw[/url]


    If you don't have time to do it right, when will you have time to do it over?

  • Now that you mention it, my trigger actually did the reverse. The person who designed one of the tables didn't normalize it properly. The trigger I wrote created a view to normalize it.

    Drew

    J. Drew Allen
    Business Intelligence Analyst
    Philadelphia, PA

Viewing 9 posts - 1 through 9 (of 9 total)

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