How to transform rows to columns using Postgres SQL? - sql

I have the data in the following structure
Desired Output

Postgres (starting in 9.4) supports the filter syntax for conditional aggregation. So I would recommend:
SELECT customer_id,
MAX(value) FILTER (WHERE name = 'age') as age,
MAX(value) FILTER (WHERE name = 'marketing_consent') as marketing_consent,
MAX(value) FILTER (WHERE name = 'gender') as gender
FROM t
GROUP BY customer_id

SELECT customer_id,
MAX(CASE WHEN name='age' THEN value ELSE NULL END) AS age,
MAX(CASE WHEN name='marketing_consent' THEN value ELSE NULL END) AS marketing_consent,
MAX(CASE WHEN name='gender' THEN value ELSE NULL END) AS gender
FROM table
GROUP BY customer_id;
You just group by customer_id and pick out each value in its own column. You need an aggregate function on the various values columns for syntactical reasons, which is why each column has a Max function.
Not e that it would of course be better to store the data in a normalized fashion. Also, with newer versions of postgres, you can use filter instead of case, which I find a bit more readable.

Related

Row data into Column

I have this list of student and i want to make the Date record as the column
I want the result to be like this
SQL queries demand that you know the columns to select beforehand. If you know exactly which dates to expect, then you can select them as columns using Pivot or conditional aggregation:
select
max(case when date = {d '2015-08-01'} then student_id end) as date20150801,
max(case when date = {d '2015-08-02'} then student_id end) as date20150802,
...
from mytable
group by student_id;
Usually, however, you would simply select the data as rows with SQL and care about the presentation as columns in a grid with your GUI language (Java, C#, PHP, whatever).

How to do a Postgresql group aggregation: 2 fields using one to select the other

I have a table - Data - of rows, simplified, like so:
Name,Amount,Last,Date
A,16,31,1-Jan-2014
A,27,38,1-Feb-2014
A,12,34,1-Mar-2014
B,8,37,1-Jan-2014
B,3,38,1-Feb-2014
B,17,39,1-Mar-2014
I wish to group them similar to:
select Name,sum(Amount),aggr(Last),max(Date) from Data group by Name
For aggr(Last) I want the value of 'Last' from the row that contains max(Date)
So the result I want would be 2 rows
Name,Amount,Last,Date
A,55,34,1-Mar-2014
B,28,39,1-Mar-2014
i.e. in both cases, the value of Last is the one from the row that contained 1-Mar-2014
The query I'm actually doing is basically the same, but with many more sum() fields and millions of rows, so I'm guessing an aggregate function could avoid multiple extra requests each group of incoming rows.
Instead, use row_number() and conditional aggregation:
select Name, sum(Amount),
max(case when seqnum = 1 then Last end) as Last,
max(date)
from (select d.*, row_number() over (partition by name order by date desc) as seqnum
from data d
) d
group by Name;

COUNT() doesn't work with GROUP BY?

SELECT COUNT(*) FROM table GROUP BY column
I get the total number of rows from table, not the number of rows after GROUP BY. Why?
Because that is how group by works. It returns one row for each identified group of rows in the source data. In this case, it will give the count for each of those groups.
To get what you want:
select count(distinct column)
from table;
EDIT:
As a slight note, if column can be NULL, then the real equivalent is:
select (count(distinct column) +
max(case when column is null then 1 else 0 end)
)
from table;
Try this:
SELECT COUNT(*), column
FROM table
GROUP BY column

Pivot without aggregate - again

I have a table where I want to pivot some rows. There are lots of these questions on here, but I am still struggling.
Here is the table that I am starting from.
Here is where I want to get to
Based on your sample data, you can easily get the result using an aggregate function with a CASE expression:
select userlicenseid,
startdate,
max(case when name = 'Other' then value end) Other,
max(case when name = 'Pathways' then value end) Pathways,
max(case when name = 'Execution' then value end) Execution,
max(case when name = 'Focus' then value end) Focus,
max(case when name = 'Profit' then value end) Profit
from yourtable
group by userlicenseid, startdate;
See SQL Fiddle with Demo. Since you are converting string values into columns, then you will want to use either the min() or max() aggregate.
You could use the PIVOT function to get the result as well:
select userlicenseid, startdate,
Other, Pathways, Execution, Focus, Profit
from
(
select userlicenseid, startdate,
name, value
from yourtable
) d
pivot
(
max(value)
for name in (Other, Pathways, Execution, Focus, Profit)
) piv;
See SQL Fiddle with Demo

unique count of the columns?

i want to get a unique count of the of multiple columns containing the similar or different data...i am using sql server 2005...for one column i am able to take the unique count... but to take a count of multiple columns at a time, what's the query ?
You can run the following selected, getting the data from a derived table:
select count(*) from (select distinct c1, c2, from t1) dt
To get the count of combined unique column values, use
SELECT COUNT(*) FROM TableName GROUP BY UniqueColumn1, UniqueColumn2
To get the unique counts of multiple individual columns, use
SELECT COUNT(DISTINCT Column1), COUNT(DISTINCT Column2)
FROM TableName
Your question is not clear what exactly you want to achieve.
I think what you're getting at is individual SUMS from two unique columns in one query. I was able to accomplish this be using
SELECT FiscalYear, SUM(Col1) AS Col1Total, SUM(Col2) AS Col2Total
FROM TableName
GROUP BY FiscalYear
If your data is not numerical in nature, you can use CASE statements
SELECT FiscalYear, SUM(CASE WHEN ColA = 'abc' THEN 1 ELSE 0 END) AS ColATotal,
SUM(CASE WHEN ColB = 'xyz' THEN 1 ELSE 0 END) AS ColBTotal
FROM TableName
GROUP BY FiscalYear
Hope this helps!