Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rows Into Columns and Grouping

Tags:

sql

sql-server

I have a query that looks like this:

SELECT OrganizationName, OrganizationID, ReceivableStatus, InvoiceFee
FROM v_InvoicesFreelanceOutstanding
ORDER BY OrganizationID

The data from that might look like this:

OrganizationName    OrganizationID        ReceivableStatus       InvoiceFee
-----------------------------------------------------------------------------
Company A                      139        60-90 days                 672.00
Company A                      139        60-90 days                1800.00
Company A                      139        over 90 days              1440.00
Company B                      264        Current                   3559.38
Company B                      264        60-90 days                3785.50
Company C                      271        60-90 days                 446.25
Company C                      271        over 90 days               637.50
Company C                      271        over 90 days              1126.25

What I want to eventually display is something like this (for the data above):

Company     Current    30-60 days    60-90 days    over 90 days       Total   
-----------------------------------------------------------------------------
Company A         0             0       2472.00               0     2472.00
Company B   3559.38             0       3785.50               0     7344.88
Company C         0             0        446.25         1763.75     2210.00

My SQL-fu is not enough to get me past this:

SELECT
    MAX(OrganizationName) as OrganizationName,
    OrganizationID,
    ReceivableStatus,
    SUM(InvoiceFee) as TotalDue
FROM v_InvoicesFreelanceOutstanding
GROUP BY OrganizationID, ReceivableStatus

Which shows something like this (again, from the data above):

OrganizationName    OrganizationID        ReceivableStatus         TotalDue
-----------------------------------------------------------------------------
Company A                      139        60-90 days                2472.00
Company A                      139        over 90 days              1440.00
Company B                      264        Current                   3559.38
Company B                      264        60-90 days                3785.50
Company C                      271        60-90 days                 446.25
Company C                      271        over 90 days              1763.75

What then? Any help would be appreciated.

Note that the statuses shown in the 2nd table (Current, 30-60 days, 60-90 days, over 90 days) are the only ones I'm expecting to come up under ReceivableStatus.

EDIT: Sorry for not including this. I am aware of PIVOT but I couldn't get it to do what I want.

like image 617
Paolo Bergantino Avatar asked Mar 20 '09 14:03

Paolo Bergantino


People also ask

What is grouping in Excel?

The “Group” is an Excel tool which groups two or more rows or columns. With grouping, the user has an option to minimize and maximize the grouped data. The rows or columns of the group collapse on minimizing and expand on maximizing. The “group” option is available under the “outline” section of the Data tab.

How do you group rows based on column values in Excel?

Select Home > Group by. In the Group by dialog box, select Advanced to select more than one column to group by. To add another column, select Add Grouping. Tip To delete or move a grouping, select More (…)

How do I group rows in Excel?

On the Data tab, in the Outline group, click Group. Then in the Group dialog box, click Rows, and then click OK. Tip: If you select entire rows instead of just the cells, Excel automatically groups by row - the Group dialog box doesn't even open. The outline symbols appear beside the group on the screen.


2 Answers

PIVOT sucks. It has horrible syntax and isn't a PIVOT in the pivot table sense i.e. you have to know exactly how many columns will result in advance.

It's probably easier to do a cross-tab report.

SELECT 
OrganizationName,
OrganizationID,
SUM(CASE WHEN ReceivableStatus       = '30-60 days' THEN InvoiceFee ELSE 0 END) AS [30 - 60 Days],
SUM(CASE WHEN ReceivableStatus       = '60-90 days' THEN InvoiceFee ELSE 0 END) AS [60 - 90 Days],
SUM(CASE WHEN ReceivableStatus       = '90-120 days' THEN InvoiceFee ELSE 0 END) AS [90 - 120 Days]

FROM
v_InvoicesFreelanceOutstanding
GROUP BY OrganizationID
like image 92
adolf garlic Avatar answered Sep 18 '22 14:09

adolf garlic


This looks like a job for pivot if you're using SQL Server 2005 or later.

EDIT:

Since you already know about pivot, you know it does almost what you need.

You already have the following query:

SELECT
    MAX(OrganizationName) as OrganizationName,
    OrganizationID,
    ReceivableStatus,
    SUM(InvoiceFee) as TotalDue
FROM v_InvoicesFreelanceOutstanding
GROUP BY OrganizationID, ReceivableStatus

Which gives you the current, 30-60, 60-90 and 90+ parts that you need. If you pivot that, you get everything you need except for your total. So just throw in the total:

(SELECT
    MAX(OrganizationName) as OrganizationName,
    OrganizationID,
    ReceivableStatus,
    SUM(InvoiceFee) as TotalDue
FROM v_InvoicesFreelanceOutstanding
GROUP BY OrganizationID, ReceivableStatus)
UNION
(SELECT
    MAX(OrganizationName) as OrganizationName,
    OrganizationID,
    'Total' AS ReceivableStatus,
    SUM(InvoiceFee) as TotalDue
FROM v_InvoicesFreelanceOutstanding
GROUP BY OrganizationID)

Pivot on this result and you should get the output you want:

SELECT *
FROM 
    [the query above]
PIVOT (
    SUM(TotalDue)
    FOR ReceivableStatus IN ([Current],[30-60 days],[60-90 days],[over 90 days],[Total]) 
)
like image 34
Welbog Avatar answered Sep 22 '22 14:09

Welbog