How to group output and create columns from results [duplicate] - mysql

I have a simple query that produces the below results:
SELECT month,transporttype,count(transporttype) as loads
from deliveries
group by month,transporttype
I would like to transpose the rows into columns.
I understand mysql does not have pivot functions so a union is required but not 100% sure.
Thanks in advance for the help.

You can do it with a crosstab like this -
SELECT
`year`,
`month`,
SUM(IF(`transporttype` = 'inbound', 1, 0)) AS `inbound`,
SUM(IF(`transporttype` = 'LocalPMB', 1, 0)) AS `LocalPMB`,
SUM(IF(`transporttype` = 'Long Distance', 1, 0)) AS `Long Distance`,
SUM(IF(`transporttype` = 'shuttle', 1, 0)) AS `shuttle`,
SUM(IF(`transporttype` = 'export', 1, 0)) AS `export`,
SUM(IF(`transporttype` = 'Extrusions-LongDistance', 1, 0)) AS `Extrusions-LongDistance`,
SUM(IF(`transporttype` = 'Extrusions-Shuttle', 1, 0)) AS `Extrusions-Shuttle`
FROM `deliveries`
GROUP BY `year`, `month`
On a different note, you should move transporttype values to a lookup table and have transporttype_id in this table.

Related

SQL query to break down day by day for entire week

I have a table of sales in MySQL. I'm trying in 1 query to get a view that looks like this:
AGENT, MONDAY_TOTAL, TUESDAY_TOTAL,WEDNESDAY_TOTAL,THURSDAY_TOTAL,FRIDAY_TOTAL,SATURDAY_TOTAL
What I have so far is this:
SELECT DISTINCT(repname), DAYOFWEEK(sub_date), COUNT(*)
FROM `NewDeals`
WHERE WEEK(sub_date) = WEEK(CURRENT_DATE)
GROUP BY repname, DAYOFWEEK(sub_date)
That gives me values that look like this:
AGENT, DAYOFWEEK, TOTAL
Naturally, I can turn the output of the second example into the first in my code, but if I can just do it with the SQL query I'd rather do that.
SELECT repname,
SUM(IF(DAYOFWEEK(sub_date)=2, 1, 0)) AS MONDAY_TOTAL,
SUM(IF(DAYOFWEEK(sub_date)=3, 1, 0)) AS TUESDAY_TOTAL,
SUM(IF(DAYOFWEEK(sub_date)=4, 1, 0)) AS WEDNESDAY_TOTAL,
SUM(IF(DAYOFWEEK(sub_date)=5, 1, 0)) AS THURSDAY_TOTAL,
SUM(IF(DAYOFWEEK(sub_date)=6, 1, 0)) AS FRIDAY_TOTAL,
SUM(IF(DAYOFWEEK(sub_date)=7, 1, 0)) AS SATURDAY_TOTAL,
SUM(IF(DAYOFWEEK(sub_date)=1, 1, 0)) AS SUNDAY_TOTAL
FROM `NewDeals`
WHERE WEEK(sub_date) = WEEK(CURRENT_DATE)
GROUP BY repname
But getting results for days that haven't happened yet.
Update: This was because we did not constrain the year:
Solution:
SELECT repname,
SUM(IF(DAYOFWEEK(sub_date)=2, 1, 0)) AS MONDAY_TOTAL,
SUM(IF(DAYOFWEEK(sub_date)=3, 1, 0)) AS TUESDAY_TOTAL,
SUM(IF(DAYOFWEEK(sub_date)=4, 1, 0)) AS WEDNESDAY_TOTAL,
SUM(IF(DAYOFWEEK(sub_date)=5, 1, 0)) AS THURSDAY_TOTAL,
SUM(IF(DAYOFWEEK(sub_date)=6, 1, 0)) AS FRIDAY_TOTAL,
SUM(IF(DAYOFWEEK(sub_date)=7, 1, 0)) AS SATURDAY_TOTAL,
SUM(IF(DAYOFWEEK(sub_date)=1, 1, 0)) AS SUNDAY_TOTAL
FROM `NewDeals`
WHERE WEEK(sub_date) = WEEK(CURRENT_DATE) AND YEAR(sub_date) = YEAR(CURRENT_DATE)
GROUP BY repname
You can use an IF function to select only DAYOFWEEK-related counts, then sum every counted element inside the SUM aggregate function as follows:
SELECT repname,
SUM(IF(DAYOFWEEK(sub_date)=2, 1, 0)) AS MONDAY_TOTAL,
SUM(IF(DAYOFWEEK(sub_date)=3, 1, 0)) AS TUESDAY_TOTAL,
SUM(IF(DAYOFWEEK(sub_date)=4, 1, 0)) AS WEDNESDAY_TOTAL,
SUM(IF(DAYOFWEEK(sub_date)=5, 1, 0)) AS THURSDAY_TOTAL,
SUM(IF(DAYOFWEEK(sub_date)=6, 1, 0)) AS FRIDAY_TOTAL,
SUM(IF(DAYOFWEEK(sub_date)=7, 1, 0)) AS SATURDAY_TOTAL,
SUM(IF(DAYOFWEEK(sub_date)=1, 1, 0)) AS SUNDAY_TOTAL
FROM `NewDeals`
WHERE WEEK(sub_date) = WEEK(CURRENT_DATE)
GROUP BY repname
Note: when the DISTINCT keyword is applied, it will work on every selected field of your SELECT clause, you can't make a distinct of a single field using parentheses.

How to improve/simplify a query with a lot of subquerys?

I have a sql query that sum and counts some registers from my db, the problem is that I'm using a lot of subquerys and all of them have the same condition, I need to find a better solution because this is causing slowness in my system.
I tried to use a simple left join but mysql returned a single row and I want that counts and sum every register on the table dbgeneralesImportacion.
I have something like this:
SELECT dbgeneralesImportacion.id,
sapito.dbgeneralesImportacion.documentosCompletos AS 'documentosCompletos',
(SELECT COUNT(c.id)
FROM sapito.dbcontenedores c
WHERE c.operacion = dbgeneralesImportacion.id ) AS 'ContadorContenedores',
(SELECT SUM(IF(c.estatus = 1, 1, 0))
FROM sapito.dbcontenedores c
WHERE c.operacion = dbgeneralesImportacion.id ) AS 'ContadorDespachos',
(SELECT SUM(IF(c.estatus = 2, 1, 0))
FROM sapito.dbcontenedores c
WHERE c.operacion = dbgeneralesImportacion.id ) AS 'ContadorCompletado',
(SELECT SUM(IF(c.desconsolidacion = 1, 1, 0))
FROM sapito.dbcontenedores c
WHERE c.operacion = dbgeneralesImportacion.id ) AS 'DesconsolidacionPuerto',
(SELECT SUM(c.bultos) FROM sapito.dbcontenedores c WHERE c.operacion = dbgeneralesImportacion.id) AS 'bultos'
FROM dbgeneralesImportacion
And my idea was to do this but counts all register and return a single row:
SELECT dbgeneralesImportacion.id AS 'id',
COUNT(c.id) AS 'ContadorContenedores',
SUM(IF(c.estatus = 1, 1, 0)) AS 'ContadorDespachos',
SUM(IF(c.estatus = 2, 1, 0)) AS 'ContadorCompletado',
SUM(IF(c.desconsolidacion = 1, 1, 0)) AS 'DesconsolidacionPuerto',
SUM(c.bultos) AS 'bultos'
FROM dbgeneralesImportacion
LEFT JOIN dbcontenedores c ON c.operacion = dbgeneralesImportacion.id
Thank you everyone
You could use a join a and group by
SELECT a.id
, a.documentosCompletos
, COUNT(c.id) ContadorContenedores
, SUM(IF(c.estatus = 1, 1, 0)) ContadorDespachos
, SUM(IF(c.estatus = 2, 1, 0)) ContadorCompletado
, SUM(IF(c.desconsolidacion = 1, 1, 0)) DesconsolidacionPuerto
, SUM(c.bultos) bultos
FROM dbgeneralesImportacion a
INNER JOIN sapito.dbcontenedores c ON c.operacion = a.id
GRUP BY a.id, a.documentosCompletos
Not positive, but couldn't you do something like this
SELECT dbgeneralesImportacion.id,
sapito.dbgeneralesImportacion.documentosCompletos AS 'documentosCompletos',
COUNT(c.id) AS 'ContadorContenedores',
SUM(IF(c.estatus = 1, 1, 0)) AS 'ContadorDespachos',
SUM(IF(c.estatus = 2, 1, 0)) AS 'ContadorCompletado',
SUM(IF(c.desconsolidacion = 1, 1, 0)) AS 'DesconsolidacionPuerto',
SUM(c.bultos) AS 'bultos'
FROM dbgeneralesImportacion, sapito.dbcontenedores c
WHERE c.operacion = dbgeneralesImportacion.id
GROUP BY dbgeneralesImportacion.id
You need a GROUP BY, but you can also simplify the query:
SELECT gi.id AS id,
COUNT(c.id) AS ContadorContenedores,
SUM( c.estatus = 1 ) AS ContadorDespachos,
SUM( c.estatus = 2 ) AS ContadorCompletado,
SUM( c.desconsolidacion = 1 ) AS DesconsolidacionPuerto,
SUM(c.bultos) AS bultos
FROM dbgeneralesImportacion LEFT JOIN
dbcontenedores c
ON c.operacion = gi.id
GROUP BY gi.id;
MySQL treats boolean values as numbers in a numeric context, with true being 1 and false being 0. This makes it easy to count up matching values.
Also, only use single quotes for string and date constants. Using them for column aliases can lead to hard-to-debug problems.

How to SUM result both SUMs SQL?

Using this query I try to sum result of both SUM function:
select
DAY(created_at) AS day,
SUM(if(status = '1', 1, 0)) AS result,
SUM(if(status = '2', 1, 0)) AS noresult,
SUM(result + noresult)
from `clients` where `doctor_id` = 2 and MONTH(created_at) = MONTH(CURRENT_TIMESTAMP) group by `day`
I try to do that in this line:
SUM(result + noresult)
Try this:
select
DAY(created_at) AS day,
SUM(if(status = '1', 1, 0)) AS result,
SUM(if(status = '2', 1, 0)) AS noresult,
SUM(if(status in ('1', '2'), 1, 0))
from `clients`
where `doctor_id` = 2 and MONTH(created_at) = MONTH(CURRENT_TIMESTAMP)
group by `day`
You can't use alias in select columns name you must repeat the code
select
DAY(created_at) AS day,
SUM(if(status = '1', 1, 0)) AS result,
SUM(if(status = '2', 1, 0)) AS noresult,
SUM(if(status = '1', 1, 0)) + SUM(if(status = '2', 1, 0)) AS all_result
from `clients` where `doctor_id` = 2 and MONTH(created_at) = MONTH(CURRENT_TIMESTAMP) group by `day`
you must repeat the code because the different SQL clause are processed in a specific order (first from then where then select and and group by .... etc.. ) so at the moment of the select parsing the alias are not available to the sql engine
As several other people have stated, you cannot use aliases in your select statement. However, to keep it cleaner, you could combine both conditions rather than summing both SUM fields.
select
DAY(created_at) AS day,
SUM(if(status = '1', 1, 0)) AS result,
SUM(if(status = '2', 1, 0)) AS noresult,
SUM(if(status = '1' OR status = '2', 1, 0)) AS newcolumn
from `clients` where `doctor_id` = 2 and MONTH(created_at) = MONTH(CURRENT_TIMESTAMP) group by `day`

mysql use logic in where clause + invalid use of group function

I have the below mysql query that outputs the below image:
select
v.invoicenumber,
v.invoicedate,
v.haulier,
v.transporttype,
count(v.loadnumber) as totalloads,
sum(v.cost) as totalcost,
concat(SUM(if(invoiceapproved = 'yes', 1, 0)),' / ',count(v.loadnumber)) AS count, SUM(if(invoiceapproved = 'yes', 1, 0)) as approved
from v2loads v
where v.invoiced='yes'
group by invoicenumber
This query excutes 100%.
what I want to do is filter out any rows / data where the count is 100%. in the example output I want to filter out invoice 16 as it is 2/2 and 100%. so where
count(v.loadnumber) <> SUM(if(invoiceapproved = 'yes', 1, 0))
if I add this logic into the where clause it fails with error invalid use of group function. so below code does not work:
select v.invoicenumber,
v.invoicedate,
v.haulier,
v.transporttype,
count(v.loadnumber) as totalloads,
sum(v.cost) as totalcost,
concat(SUM(if(invoiceapproved = 'yes', 1, 0)),' / ',count(v.loadnumber)) AS count,
SUM(if(invoiceapproved = 'yes', 1, 0)) as approved
from v2loads v
where v.invoiced='yes' and
(count(v.loadnumber))<>(SUM(if(invoiceapproved = 'yes', 1, 0)))
group by invoicenumber
I got the following error:
error is #1111 - Invalid use of group function.
Any advice appreciated as always.
You can do this:
SELECT
*,
CONCAT(approved, ' / ', totalloads) AS count,
FROM
(
SELECT
v.invoicenumber,
v.invoicedate,
v.haulier,
v.transporttype,
COUNT(v.loadnumber) AS totalloads,
SUM(v.cost) AS totalcost,
SUM(if(invoiceapproved = 'yes', 1, 0)) As approved
FROM v2loads v
WHERE v.invoiced='yes'
GROUP BY invoicenumber
) t
WHERE totalloads <> approved;
select v.invoicenumber,
v.invoicedate,
v.haulier,
v.transporttype,
count(v.loadnumber) as totalloads,
sum(v.cost) as totalcost,
concat(SUM(if(invoiceapproved = 'yes', 1, 0)),' / ',count(v.loadnumber)) AS count,
SUM(if(invoiceapproved = 'yes', 1, 0)) as approved
from v2loads v
where v.invoiced='yes'
group by invoicenumber
having (count(v.loadnumber))<>(SUM(if(invoiceapproved = 'yes', 1, 0)))

Multiple nested if statment in MySQL query

I'm trying the query below and MySQL gave me this error: Invalid use of group function
SELECT C.`some_name`,
SUM(IF(A.`med_type` = 1, SUM(A.`med_qty`), 0)) AS total,
SUM(IF(A.`is_rejected` = 4, 1 , 0)) AS approved,
SUM(IF(A.`is_rejected` = 2, 1 , 0)) AS qeue,
SUM(IF(A.`is_rejected` = 3, 1 , 0)) AS rejected,
SUM(IF(A.`is_rejected` = 1, 1 , 0)) AS fresh
FROM `ne_media` A
INNER JOIN `ne_member` B ON A.`mem_id` = B.`mem_id`
INNER JOIN `ne_some` C ON B.`some_id` = C.`some_id`
GROUP BY C.`some_id`;
I want to sum med_qty just if med_type = 1.
How do I do it?
Use:
SUM(CASE WHEN (A.`med_type` = 1) THEN A.`med_qty` ELSE 0 END)) AS total,
or:
SUM(IF(A.`med_type` = 1, A.`med_qty`, 0)) AS total,
You can't do aggregates on aggregates like you tried to in the original.