SQL Select to spread row data to columns - mysql

I have this select
SELECT
products.prod_name, SUM(beg_inv - end_inv) AS inv,
MONTH(task_date) MONTH
FROM performances
INNER JOIN tasks
ON performances.task_id = tasks.task_id
INNER JOIN people
ON people.person_id = tasks.emp_id
INNER JOIN products
ON performances.prod_id = products.prod_id
WHERE YEAR(task_date) = '2013'
GROUP BY performances.prod_id, MONTH(task_date)
ORDER BY MONTH(task_date), prod_name
and its out put is:
Prod name inv month
Product 1 5 3
Product 1 10 5
I would want to spread it like this:
Product Name January February March April May June July August September October November December
Product 1 5 10
Is it possible without having to do a Pivot and just in select?

Just do the pivot in SQL like this:
SELECT products.prod_name,
SUM(case when MONTH(task_date) = 1 then beg_inv - end_inv end) AS January,
SUM(case when MONTH(task_date) = 2 then beg_inv - end_inv end) AS February,
SUM(case when MONTH(task_date) = 3 then beg_inv - end_inv end) AS March,
. . .
FROM performances
INNER JOIN tasks
ON performances.task_id = tasks.task_id
INNER JOIN people
ON people.person_id = tasks.emp_id
INNER JOIN products
ON performances.prod_id = products.prod_id
WHERE YEAR(task_date) = 2013
GROUP BY products.prod_name,
ORDER BY products.prod_name,;
Note that this also requires small changes to the GROUP BY and ORDER BY clauses.

Related

how to get two table joined data exclude some conditional data of one table in mysql?

I have two tables: Student and fee
student
sid
name
roll_no
1
John
22
2
Karina
32
3
Navin
42
fee
fid
s_id
month
fee
1
2
January
1000
2
3
January
1200
3
2
Fabruary
1000
I want to get students (who not paid fee) for Fabruary : like this...
Student id
Name
Roll No
January
February
1
John
22
0
0
3
Navin
42
1200
0
My code is :
SELECT s.sid,s.name,s.roll_no,f.fee
from student s
left join
fee f
ON f.fid = s.sid
AND f.month = 'January'
where s.sid NOT IN (SELECT s_id from fee
where month = 'February')
order by c.id;
I got zero value in both months for all students
------Thanks in advance-------
After correction this code works in mysql workbench but not in java application.
SELECT
s.sid,s.name,s.roll_no, ifnull(f.fee,0) as pre_month,0 as current_month
from student s
left join
fee f
ON f.s_id = s.sid
AND f.month = 'January'
where s.sid NOT IN
(SELECT s_id from fee
where month = 'February')
order by s.sid;
For the results you want, I would suggest conditional aggregation and a having clause:
SELECT s.sid, s.name, s.roll_no,
SUM(CASE WHEN f.month = 'January' THEN f.fee ELSE 0 END) as january,
SUM(CASE WHEN f.month = 'February' THEN f.fee ELSE 0 END) as february
FROM student s LEFT JOIN
fee f
ON f.fid = s.sid AND f.month = 'January'
GROUP BY s.sid, s.name, s.roll_no
HAVING SUM(CASE WHEN f.month = 'February' THEN f.fee ELSE 0 END) = 0 AND
SUM(CASE WHEN f.month = 'January' THEN f.fee ELSE 0 END) > 0;
Here is a db<>fiddle.
Note that storing month names in a column is usually a really bad idea. It does not distinguish between the years, for instance. It is much better to use a date.
You can use a left join to join the students with their fees, and then a having clause to filter the list down to those who don't have one for February. The below query should get you a list of all students who did not pay a fee for February.
It also looked like you might be using the wrong column on the fee table for the join. It looked like you might want s_id instead of fid.
select s.*
from students s
left join fee f on f.s_id=s.sid and f.month='February'
having f.fid is null;

Correct join syntax within multiple queries and sub queries

I have two queries that end up having the same format. Each has a Month, a year, and some relevant data per month/year. The schema looks like this:
subs Month Year
8150 1 2015
11060 1 2016
5 2 2014
6962 2 2015
8736 2 2016
Cans months years
2984 1 2015
2724 1 2016
13 2 2014
2563 2 2015
1901 2 2016
The first query syntax looks like this:
SELECT
COUNT(personID) AS subs_per_month,
MONTH(Date_1) AS month_1,
YEAR(Date_1) AS year_1
FROM
(SELECT
personID, MIN(date) AS Date_1
FROM
orders
WHERE
isSubscription = 1
GROUP BY personID
ORDER BY Date_1) AS my_sub_q
GROUP BY month_1 , year_1
The second query:
SELECT
COUNT(ID), MONTH(date) AS months, YEAR(date) AS years
FROM
orders
WHERE
status = 4 AND isSubscription = 1
GROUP BY months , years
ORDER BY months, years
The end goal is to write a simple join so that the final dataset looks like this:
subs cans months years
8150 2984 1 2015
11060 2724 1 2016
5 13 2 2014
6962 2563 2 2015
8736 1901 2 2016
I'm a little overwhelmed with how to do this correctly, and after a lot of trial and all error, I thought I'd ask for help. What's confusing is where the JOIN goes, and how that looks relative to the rest of the syntax.
Without giving consideration to simplifying your queries you can use your two queries as inline views and simply select from both (I aliased Q1 and Q2 for your queries and named fields the same within each for simplicity.
Select Q1.cnt as Subs, Q2.cnt as Cans, Q1.months, Q1.years
from (SELECT
COUNT(personID) AS Cnt,
MONTH(Date_1) as Months,
YEAR(Date_1) AS years
FROM (SELECT personID, MIN(date) AS Date_1
FROM orders
WHERE isSubscription = 1
GROUP BY personID) AS my_sub_q
GROUP BY month_1 , year_1) Q1
INNER JOIN (SELECT COUNT(ID) cnt, MONTH(date) AS months, YEAR(date) AS years
FROM orders
WHERE status = 4
AND isSubscription = 1
GROUP BY months, years) Q2
ON Q1.Months = Q2.Months
and Q1.Years = Q2.years
Order by Q1.years, Q2.months
Temporary table approach:
create temporary table first_query
<<your first query here>>;
create temporary table second_query
<<your second query here>>;
select fq.subs, sq.cans, fq.months, fq.years
from first_query fq
join second_query sq using (months, years)
Your table preview and query columns do not match for first query, so I assumed both tables have columns - months and years.
One messy query approach:
SELECT fq.subs_per_month subs, sq.cans, sq.months, sq.years
FROM
(SELECT
COUNT(personID) AS subs_per_month,
MONTH(Date_1) AS month_1,
YEAR(Date_1) AS year_1
FROM
(SELECT
personID, MIN(date) AS Date_1
FROM
orders
WHERE
isSubscription = 1
GROUP BY personID
ORDER BY Date_1) AS my_sub_q
GROUP BY month_1 , year_1) fq
JOIN
(SELECT
COUNT(ID) cans, MONTH(date) AS months, YEAR(date) AS years -- I added 'cans'
FROM
orders
WHERE
status = 4 AND isSubscription = 1
GROUP BY months , years
ORDER BY months, years) sq
ON fq.month_1 = sq.months AND fq.year_1 = sq.years
Please use following query
select t1.subs as subs,t2.Cans as cans,t1.months,t1.year as years from table1 t1 inner join
table2 t2 on t1.month=t2.months and t1.year=t2.years

How to print result from sql query with month name

I have a SQL query which retrieving count with month.
Ex :
January - 5
February - 2 so on.
What I need to know is, if there are no record for particular month, how to print that month and display its count as 0.
This is my query:
select
DATETNAME(MONTH, c.postTime) as Month, COUNT(c.regNo) as Count
from
Company c
where
DATENAME(YEAR, c.postTime) = 2015
group by
c.postTime
This query returns these results:
MONTH | Count
-----------------
July | 2
August | 1
The result I'm looking for should be:
MONTH | Count
-----------------
January | 0
February| 0
March | 0
April | 0
May | 0
June | 0
July | 2
August | 1
.
.
.
so on...
One way is to drive them from anchor query where all the months' list are written explicitly, then left join your table company:
SELECT m.Name, COUNT(COALESCE(c.regNo, 0)) as Count
FROM
(
VALUES ('Janurary'), ('February'), ('March'),
('April'), ('May'), ('June'),
('July'), ('August'), ('September'),
('October'), ('November'), ('December')
) AS m(Name)
LEFT JOIN Company c ON DATETNAME(MONTH, c.postTime) = m.Name
WHERE DATENAME(YEAR, c.postTime) = 2015
GROUP BY m.Name;
If the table company doesn't have any particular month, it will be shown with count 0.
You can also use a recursive CTE to generate numbers from 1 to 12 and cast these integers to month names:
;WITH CTE
AS
(
SELECT 1 AS n
UNION ALL
SELECT n + 1
FROM CTE
WHERE n < 12
), Months
AS
(
SELECT DATENAME(Month,
DATEADD(Month,
n-1,
CAST('2015-01-01' AS datetime))) AS Name
FROM CTE
)
SELECT m.Name, COUNT(COALESCE(c.regNo, 0)) as Count
FROM Months AS m
LEFT JOIN Company c ON DATETNAME(MONTH, c.postTime) = m.Name
WHERE DATENAME(YEAR, c.postTime) = 2015
GROUP BY m.Name;
SELECT m.Name, COUNT(COALESCE(c.regNo, 0)) as Count
FROM
(
VALUES ('Janurary'), ('February'), ('March'),
('April'), ('May'), ('June'),
('July'), ('August'), ('September'),
('October'), ('November'), ('December')
) AS m(Name)
LEFT JOIN Company c ON DATETNAME(MONTH, c.postTime) = m.Name
AND DATENAME(YEAR, c.postTime) = 2015
GROUP BY m.Name;
Use And instead of "Where" keyword. Then It's working as expected.

SQL sum aggregate including 0

I have two tables. One is an employee table containing the employee information and the other table is the sales the employee has made. I am trying to group the sum of sales made by an employee in a month including the months where he/she has made zero sales. Here are some of the values in the table
Employees table
number name
1 Matt
2 Foggy
3 Karen
4 Wilson
sales
employee_number month sale_number sale_amount
1 January 2015 1 300
1 January 2015 2 50
1 February 2015 1 400
2 March 2015 1 300
3 January 2015 1 50
I was able to write the query for getting the monthly sales sum using the following query
select sum(sales.sale_amount), sales.employee_number, sales.month, sales.sale_number
from sales group by employee_number, month;
Now because I also need the months including zeros I thought left outer join with the different months should do the trick. However the output still consists of the same output from before without zeros or null. Does the left outer join not join the null values?
The output should be something like this.
number name sale_amount sale_month
1 Matt 350 January 2015
1 Matt 400 February 2015
1 Matt 0 March 2015
2 Foggy 0 January 2015
2 Foggy 0 February 2015
2 Foggy 300 March 2015
and so on.
A left outer join conjures up null values for missing rows from the right hand table. To show all months, you'd switch the order of tables:
from months
cross join
employees
left outer join
sales
on sales.month = months.month
and employees.number = sales.employee_number
If you're missing a months table, you can ad-lib one from the sales table:
select months.month
, employees.name
, sum(sale_amount) as sales
from (
select distinct month
from sales
) as months
cross join
employees
left outer join
sales
on sales.month = months.month
and employees.number = sales.employee_number
group by
months.month
, employees.name
Example at SQL Fiddle.
Following query will help you:
SELECT q1.month, q1.number, q2.total_sales FROM
(SELECT distinct s.month, e.number
FROM sales s, Employees e) AS q1
LEFT JOIN
(SELECT SUM(sales.sale_amount) AS total_sales, sales.employee_number, sales.month, sales.sale_number
FROM sales group by employee_number, month) AS q2
ON (q1.month = q2.month) AND (q1.number = q2.employee_number)
ORDER BY month, number;
check the fiddle

showing one column several times with data from 3 different date intervals

I am trying to show three different figures of the same column In a mysql query and joining all three tables, I would like to keep one month static: April, so it would be a case like this I want to show The current month, the previous month and the static month of the year I'm working with, in this case let us stick with 2012
table: persons
ID name
1 Carl
table: vehicle
ID v_name person_veh
100 Dodge Viper 1
Table:payment
pay_id , pay_date, amount person_id
1 2012-02-12 1000 1
2 2012-03-11 780 1
3 2012-04-15 890 1
4 2012-05-12 1200 1
5 2012-06-12 1890 1
6 2012-07-12 1350 1
7 2012-08-12 1450 1
So what I want to do is show the column amount for the month of April as I said I want to keep that row static: 890, the current month lets say the current month is August:1450 and the previous month amount which would be July:1350: so the final result would be something like this:
name v_name april_amount current_month_amount previous_month_amount
Carl Dodge viper 890 1450 1350
You can use the following - which uses an aggregate function with a CASE statement:
select p.name,
v.v_name,
sum(case when Month(py.pay_date) = 4 then amount end) april_amount,
sum(case when Month(py.pay_date) = Month(curdate())
then amount end) current_month_amount,
sum(case when Month(py.pay_date) = Month(curdate())-1
then amount end) previous_month_amount
from persons p
left join vehicle v
on p.id = v.person_veh
left join payment py
on p.id = py.person_id
group by p.name,
v.v_name
see SQL Fiddle with Demo
Try
SELECT a.name, b.pay_date, b.amount, b.person_id, c.v_name
FROM persons a
LEFT JOIN payment b on a.id = b.person_id
LEFT JOIN vehicle c on a.id = c.person_veh
This query assumes id, person_veh and person_id are the like columns which links this user across these three tables