Merge multiple columns in one single column SQL - sql

I'm having a hard time solving this, i hope someone can help me out with some tips or advice.
I have a Table in SQL with 3 columns:
Pencil Sales Notebook Sales Pen Sales
1 2 3
9 5 6
7 8 9
I made a query using "Union all" with the sum of each column.
My query looks like this:
select sum(pencilsales) from table1 union all
select sum(notebooksales) from table1 union all
select sum(pensales) from table1
and it gives me the following:
(No Column Name)
17
15
18
But i wanna know if there's a way of sorting this new query by using "desc" or something like that and to add a new column saying which one is each row, like this:
Sales Name
18 Pen Sales
17 Pencil Sales
15 Notebook Sales
Hope you can help me out with ideas and thank you in advance :)

select * from
(
select 'Pencil Sales' as Name, sum(pencilsales) as sales from table1
union all
select 'Notebook Sales', sum(notebooksales) from table1
union all
select 'Pen Sales', sum(pensales) from table1
) t order by sales desc

This is a pretty good candidate for UNPIVOT
SELECT
SUM(Sales) Sales,
[Name]
FROM Table1
UNPIVOT (
Sales
FOR [Name] IN ([pencilsales], [notebooksales], [pensales])
) up
GROUP BY [Name]

You can't unpivot in MySql. The sub-query gets what you want.

UNION is often not used in this case. SQL Server has the handy PIVOT/UNPIVOT to do this.
Also, your question is easier to understand if you have a key like "Sales Associate".
CREATE TABLE Sales
(
[Sales Assoicate Id] varchar(10),
[Pencil Sales] int,
[Notebook Sales] int,
[Pen Sales] int
);
INSERT INTO Sales ([Sales Associate Id],[Pencil Sales],[Notebook Sales],[Pen Sales]) VALUES ('Morgan',1,2,3);
INSERT INTO Sales ([Sales Associate Id],[Pencil Sales],[Notebook Sales],[Pen Sales]) VALUES ('Jane',9,5,6);
INSERT INTO Sales ([Sales Associate Id],[Pencil Sales],[Notebook Sales],[Pen Sales]) VALUES ('Jeff',7,8,9);
Looks like:
Sales Associate Id Pencil Sales Notebook Sales Pen Sales
Morgan 1 2 3
Jane 9 5 6
Jeff 7 8 9
To get the results how you asked for them use UNPIVOT!
SELECT SUM(Sales) Sales,
Name
FROM Sales
UNPIVOT
(Sales FOR Name IN ([Pencil Sales],[Notebook Sales],[Pen Sales])) SalesSummary
GROUP BY Name
Results:
Sales Name
15 Notebook Sales
18 Pen Sales
17 Pencil Sales

Related

SQL query to duplicate each row 12 times

I have a table which has columns site,year and sales . this table is unique on site+year eg
site year sales
-------------------
a 2012 50
b 2013 100
a 2006 35
Now what I want to do is make this table unique on site+year+month. Thus each row gets duplicated 12 times, a month column is added which is labelled from 1-12 and the sales values get divided by 12 thus
site year month sales
-------------------------
a 2012 1 50/12
a 2012 2 50/12
...
a 2012 12 50/12
...
b 2013 1 100/12
...
a 2006 12 35/12
I am doing this on python currently and it works like a charm, but I need to do this in SQL (ideally PostgreSQL since I will be using this as a datasource for tableau)
It would be very helpful if someone can provide the explanations with the solution as well, since I am a novice at this
You can use generate_series() for that
select t.site, t.year, g.month, t.sales / 12
from the_table t
cross join generate_series(1,12) as g (month)
order by t.site, t.year, g.month;
If the column sales is an integer, you should cast that to a numeric to avoid the integer division: t.sales::numeric / 12
Online example: http://rextester.com/GUWPI39685
Try this approach (For T-SQL - MS SQL) :
DECLARE #T TABLE
(
[site] VARCHAR(5),
[year] INT,
sales INT
)
INSERT INTO #T
VALUES('A',2012,50),('B',2013,100),('C',2006,35)
;WITH CTE
AS
(
SELECT
MonthSeq = 1
UNION ALL
SELECT
MonthSeq = MonthSeq+1
FROM CTE
WHERE MonthSeq <12
)
SELECT
T.[site],
T.[year],
[Month] = CTE.MonthSeq,
sales = T.[sales]/12
FROM CTE
CROSS JOIN #T T
ORDER BY T.[site],CTe.MonthSeq

How can I produce rows that sum subgroups of rows, without grouping?

Let's say I have a table like this:
ID Income Expenses
-------------------------
1 $1000 $200
1 $2000 $400
2 $500 $200
2 $100 $60
I'd like to add one row per ID that sums the ID's Income and Expenses. For example:
ID Income Expenses
-------------------------
1-SUM $3000 $600
1 $1000 $200
1 $2000 $400
2-SUM $600 $260
2 $500 $200
2 $100 $60
Is this possible with SQL? I read about OVER and PARTITION BY but that'll add a new column, not a new row. Might a UNION be the best way to go here?
Try this
create table yourtable(id int,income int,expenses int)
insert into yourtable values (1,100,200),(1,150,250),(2,200,300),(2,250,350)
with CTE
as
(select ID,sum(income) as income,sum(expenses) as expenses,1 as isSum
from yourtable
group by id
)
select * from (
select *,0 as isSum from yourtable
union all
select * from CTE ) as t
order by id,issum
output
Using GROUP BY:
SQLFiddleDemo
CREATE TABLE tab(id INT , income INT , expenses INT);
INSERT INTO tab(id, income, expenses)
VALUES (1, 1000, 200),(1, 2000, 400),(2, 500, 200),(2, 100, 60)
SELECT id,
[income] = SUM(income),
[expenses] = SUM(expenses),
[grouping_level] = GROUPING_ID(id, income, expenses) /* 0 - actual data , 3 - group based on column income, expenses*/
FROM tab
GROUP BY GROUPING SETS ((id), (id,income, expenses))
Why grouping is useful:
Using GROUPING SETS gives great flexibility for instance when you want total sum use: GROUP BY GROUPING SETS ((id), (id,income, expenses), ())
GROUPING SETS can be combined with ROLLUP/CUBE.
GROUPING_ID indicates grouping level.
Number works like binary. GROUPING(a, b, c) if b i c is used for grouping you get 011B => 3

Invalid count and sum in cross tab query using PostgreSQL

I am using PostgreSQL 9.3 version database.
I have a situation where I want to count the number of products sales and sum the amount of product and also want to show the cities in a column where the product have sale.
Example
Setup
create table products (
name varchar(20),
price integer,
city varchar(20)
);
insert into products values
('P1',1200,'London'),
('P1',100,'Melborun'),
('P1',1400,'Moscow'),
('P2',1560,'Munich'),
('P2',2300,'Shunghai'),
('P2',3000,'Dubai');
Crosstab query:
select * from crosstab (
'select name,count(*),sum(price),city,count(city)
from products
group by name,city
order by name,city
'
,
'select distinct city from products order by 1'
)
as tb (
name varchar(20),TotalSales bigint,TotalAmount bigint,London bigint,Melborun bigint,Moscow bigint,Munich bigint,Shunghai bigint,Dubai bigint
);
Output
name totalsales totalamount london melborun moscow munich shunghai dubai
---------------------------------------------------------------------------------------------------------
P1 1 1200 1 1 1
P2 1 3000 1 1 1
Expected Output:
name totalsales totalamount london melborun moscow munich shunghai dubai
---------------------------------------------------------------------------------------------------------
P1 3 2700 1 1 1
P2 3 6860 1 1 1
Your first mistake seems to be simple. According to the 2nd parameter of the crosstab() function, 'Dubai' must come as first city (sorted by city). Details:
PostgreSQL Crosstab Query
The unexpected values for totalsales and totalamount represent values from the first row for each name group. "Extra" columns are treated like that. Details:
Pivot on Multiple Columns using Tablefunc
To get sums per name, run window functions over your aggregate functions. Details:
Get the distinct sum of a joined table column
select * from crosstab (
'select name
,sum(count(*)) OVER (PARTITION BY name)
,sum(sum(price)) OVER (PARTITION BY name)
,city
,count(city)
from products
group by name,city
order by name,city
'
-- ,'select distinct city from products order by 1' -- replaced
,$$SELECT unnest('{Dubai,London,Melborun
,Moscow,Munich,Shunghai}'::varchar[])$$
) AS tb (
name varchar(20), TotalSales bigint, TotalAmount bigint
,Dubai bigint
,London bigint
,Melborun bigint
,Moscow bigint
,Munich bigint
,Shunghai bigint
);
Better yet, provide a static set as 2nd parameter. Output columns are hard coded, it may be unreliable to generate data columns dynamically. If you a another row with a new city, this would break.
This way you can also order your columns as you like. Just keep output columns and 2nd parameter in sync.
Honestly I think your database needs some drastic normalization and your results in several columns (one for each city name) is not something I would do myself.
Nevertheless if you want to stick to it you can do it this way.
For the first step you need get the correct amounts. This would do the trick quite fast:
select name, count(1) totalsales, sum(price) totalAmount
from products
group by name;
This will be your result:
NAME TOTALSALES TOTALAMOUNT
P2 3 6860
P1 3 2700
You would get the Products/City this way:
select name, city, count(1) totalCityName
from products
group by name, city
order by name, city;
This result:
NAME CITY TOTALCITYNAME
P1 London 1
P1 Melborun 1
P1 Moscow 1
P2 Dubai 1
P2 Munich 1
P2 Shunghai 1
If you really would like a column per city you could do something like:
select name,
count(1) totalsales,
sum(price) totalAmount,
(select count(1)
from Products a
where a.City = 'London' and a.name = p.name) London,
...
from products p
group by name;
But I would not recommend it!!!
This would be the result:
NAME TOTALSALES TOTALAMOUNT LONDON ...
P1 3 2700 1
P2 3 6860 0
Demonstration here.

How can I combine 3 queries into one query and the result form look like schedule table?

I have 3 select queries :
the result of first for heading of my table.(like : select id, name from cars)
the second result show left side of my schedule table shows the date of sales (select date from dates inner join car on date.carid = car.carid where date.date1 > XXX/XX/XX for example)
the third result returns the data for inside the table. and it is the price of each car in each date.
But I don't know how to combine them?
I guess you need something like this Working SQL Server fiddle here
You need either of the following
Pivot feature of SQL Server
Aggregate function with group-by
Query: Pivot feature of SQL Server
SELECT *
FROM
(
SELECT [SALE_DATE], [CAR_NAME], [COST]
FROM CARS_SALES
) AS source
PIVOT
(
MAX(COST)
FOR [CAR_NAME] IN ([BENZ] , [BMW], [RENAULT])
) as pvt;
Query: Aggregate function with group-by
SELECT SALE_DATE,
MAX(CASE WHEN CAR_NAME = 'BENZ' THEN COST ELSE NULL END) [BENZ],
MAX(CASE WHEN CAR_NAME = 'BMW' THEN COST ELSE NULL END) [BMW],
MAX(CASE WHEN CAR_NAME = 'RENAULT' THEN COST ELSE NULL END) [RENAULT]
FROM CARS_SALES
GROUP BY SALE_DATE
Both the Queries give an
output result
as below:
SALE_DATE BENZ BMW RENAULT
09/07/2014 (null) (null) 900
09/08/2014 100 200 300
09/09/2014 400 600 (null)
09/10/2014 700 500 800
It's really unclear, but based on that you've posted, the solution would be something like this:
select cars.name, dates.date, dates.price
from dates
left join cars on (cars.carid=dates.carid)
order by cars.name, dates.date;
This gets the car's name, price and the date in one query. But I don't understand what your third query is for. If you provide more information I'll update this answer.

SQL Ranking Statement for Access- Duplicates in Results

I have a simple Access table [Parts] that stores the data
Part# CYTD_SALES CUST_NUM
I need to rank the parts in terms of CYTD Sales (Current Year To Day Sales) for each CUST_NUM (Customer Number) separately
I am using the following statement:
Rank:
(SELECT Count (*)
FROM [Parts] as R
Where [CYTD Sales] > [Parts].[CYTD Sales]
And > CUST_NUM= [Parts].[CUST_NUM] ) + 1
I ran into situation when the same amount was spent for more than 1 part by same customer, so the ranking looks like this
1 2 4 4 5
instead of
1 2 3 4 5
Is there a way to write a statement that would not allow identical rankings for the same customer?
Thank you!
Since Part# field is unique for each customer, below is the statement that worked for me:
(SELECT Count (*)
FROM [Parts] as R
Where ([CYTD Sales] > [Parts].[CYTD Sales] Or
([CYTD Sales]=[Parts].[CYTD Sales] And
[Part#]> [Parts].[Part#]))
And > CUST_NUM= [Parts].[CUST_NUM] ) + 1