MYSQL Select the Sum of Multiple Distinct Values - mysql

My table looks like this:
| id | Vendor | Issue |
|----|--------|-----------|
| 1 | Acme | Defective |
| 2 | Best | Returned |
| 3 | Ace | Other |
| 4 | Best | Returned |
| 5 | Acme | Other |
| 6 | Ace | Other |
| 7 | Best | Defective |
I need a Select statement to sum the amount of each distinct issue each vendor has had.
Output of select statement would look like this in a table:
| Vendor | Defective | Returned | Other |
|--------|-----------|----------|-------|
| Acme | 1 | 0 | 1 |
| Best | 1 | 2 | 0 |
| Ace | 0 | 0 | 2 |
Any help would be greatly appreciated.

You can use the CASE clause to separate the sums, as in:
select
vendor,
sum(case when issue = 'Defective' then 1 end) as defective,
sum(case when issue = 'Returned' then 1 end) as returned,
sum(case when issue = 'Other' then 1 end) as other
from my_table
group by vendor

Final Statement:
$sql = "select
vendor,
sum(case when issue = 'Item Defective' THEN 1 ELSE 0 END) as 'defective',
sum(case when issue = 'Incorrect Item Received' THEN 1 ELSE 0 END) as 'received',
sum(case when issue = 'Incorrect Item Ordered' THEN 1 ELSE 0 END) as 'ordered',
sum(case when issue = 'Item Not Made to Drawing' THEN 1 ELSE 0 END) as 'drawing',
sum(case when issue = 'Other' THEN 1 ELSE 0 END) as 'other'
FROM record GROUP BY vendor";

Related

Convert Row with duplicate values to Column - MySQL

I have a table 'A' that looks something like:
_______________________________________________________________
|query_id | query | response |user_response_count |
|---------------------------------------------------------------
| 1 | acne | BothBad | 2 |
| 1 | acne | BothGood | 1 |
| 2 | asthma | BothBad | 1 |
| 2 | asthma | product 1 | 1 |
| 2 | asthma | BothGood | 1 |
| 3 | bell palsy | product 2 | 2 |
| 3 | bell palsy | BothGood | 1 |
---------------------------------------------------------------
I want to write a query to get something that looks like:
__________________________________________________________________________________
| query_id | query | BothGood | BothBad | Product 1 | Product 2 |
-----------------------------------------------------------------------------------
| 1 | acne | 1 | 2 | 0 | 0 |
| 2 | asthma | 1 | 1 | 1 | 0 |
| 3 | bell palsy| 1 | 0 | 0 | 2 |
-----------------------------------------------------------------------------------
That "user_response_count" column actually says, 2 users selected "BothBad" option for "acne" query.
I know, by using max, I can change my rows to the column, but here it would be difficult to the max. Any Thoughts?
Conditional aggregation:
select query_id, query,
sum(case when response = 'BothGood' then cnt else 0 end) as BothGood,
sum(case when response = 'BothBad' then cnt else 0 end) as BothBad,
sum(case when response = 'product 1' then cnt else 0 end) as product1,
sum(case when response = 'product 2' then cnt else 0 end) as product2
from a
group by query_id, query;
You can use a conditional aggregation as
select query_id, query,
max( coalesce(case when response = 'BothGood' then user_response_count end,0) )
as BothGood,
max( coalesce(case when response = 'BothBad' then user_response_count end,0) )
as BothBad,
max( coalesce(case when response = 'product 1' then user_response_count end,0) )
as Product_1,
max( coalesce(case when response = 'product 2' then user_response_count end,0) )
as Product_2
from tableA
group by query_id, query
Demo

COUNT MAX CASE and GROUP BY for recurring type id

I have this view, resulting from a multiple join:
project_id | document_type_id
10 | 2
10 | 2
10 | 3
10 | 1
10 | 1
10 | 1
11 | 2
11 | 2
11 | 2
11 | 2
11 | 3
11 | 3
label for 1: "review"
label for 2: "interview"
label for 3: "romance"
I already obtained this table:
project_id | review | interview | romance
10 | OK | OK | OK
11 | NO | OK | OK
using the following query statement:
SELECT `project_id`, `document_type_id`,
MAX(CASE WHEN `document_type_id` = 1 THEN "OK" ELSE "NO" END) as "review",
MAX(CASE WHEN `document_type_id` = 2 THEN "OK" ELSE "NO" END) as "interview",
MAX(CASE WHEN `document_type_id` = 3 THEN "OK" ELSE "NO" END) as "romance"
FROM projectDocumentList
GROUP BY project_id
What I need now is to count every document type in each field in a table like that:
project_id | review | interview | romance
10 | 3 | 2 | 1
11 | 0 | 4 | 2
I tried and tried but I cannot find the correct sintax to obtain this result.
Some of my previous attempts...
COUNT(MAX(CASE WHEN `document_type_id` = 1 THEN "1" ELSE "NO" END)) as "review"
MAX(CASE WHEN `document_type_id` = 1 THEN (SELECT COUNT(`document_type_id`)) ELSE "NO" END) as "review"
COUNT(DISTINCT(MAX(CASE WHEN `document_type_id` = 1 THEN `document_type_id` ELSE "NO" END)) as "review"
You can use SUM()
Query
SELECT `project_id`,
SUM(CASE WHEN `document_type_id` = 1 THEN 1 ELSE 0 END) as "review",
SUM(CASE WHEN `document_type_id` = 2 THEN 1 ELSE 0 END) as "interview",
SUM(CASE WHEN `document_type_id` = 3 THEN 1 ELSE 0 END) as "romance"
FROM projectDocumentList
GROUP BY project_id
Results
| project_id | review | interview | romance |
| ---------- | ------ | --------- | ------- |
| 10 | 3 | 2 | 1 |
| 11 | 0 | 4 | 2 |
demo
Or COUNT(..) can also be used but you need to use NULL instead of 0.
This is because COUNT(..) handles 0, 1 and NULL values different then SUM(..) does.
Query
SELECT `project_id`,
COUNT(CASE WHEN `document_type_id` = 1 THEN 1 ELSE NULL END) as "review",
COUNT(CASE WHEN `document_type_id` = 2 THEN 1 ELSE NULL END) as "interview",
COUNT(CASE WHEN `document_type_id` = 3 THEN 1 ELSE NULL END) as "romance"
FROM projectDocumentList
GROUP BY project_id
Results
| project_id | review | interview | romance |
| ---------- | ------ | --------- | ------- |
| 10 | 3 | 2 | 1 |
| 11 | 0 | 4 | 2 |
demo

Rows to columns in MySQL with boolean values

I am trying to build an SQL statement (for MySQL) to solve the following problem:
I have a table transport_table with the information from which location there are transports to which other location. This table is ordered by transport_from (ascending), and then by transport_to (ascending). It is possible that some locations only receive good, others only send goods, most locations, however, send and receive goods. It is also possible to send goods to the own location.
---------------------------------
| transport_from | transport_to |
-----------------+---------------
| 1 | 2 |
-----------------+---------------
| 1 | 3 |
-----------------+---------------
| 1 | 7 |
-----------------+---------------
| 3 | 3 |
-----------------+---------------
| 3 | 5 |
-----------------+---------------
| 4 | 5 |
-----------------+---------------
| 4 | 6 |
-----------------+---------------
| 4 | 7 |
-----------------+---------------
| 5 | 3 |
-----------------+---------------
| 7 | 1 |
-----------------+---------------
| 7 | 6 |
---------------------------------
But I need the table in another format, and it would be great if this could be achieved by MySQL (if this is not possible, I could still use a real programming language). Can you help me how to get to a table indicating with boolean values if there was a transport between the two locations. to achieve this, I need to transfer the rows to the columns, and to set the boolean values if a specific row exists in the original table. But I have no idea how to achieve this.
Such a table should look like this:
----------------------------------
| id | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
-----+---+---+---+---+---+---+----
| 1 | 0 | 1 | 1 | 0 | 0 | 0 | 1 |
-----+---+---+---+---+---+---+----
| 2 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
-----+---+---+---+---+---+---+----
| 3 | 0 | 0 | 1 | 0 | 1 | 0 | 0 |
-----+---+---+---+---+---+---+----
| 4 | 0 | 0 | 0 | 0 | 1 | 1 | 1 |
-----+---+---+---+---+---+---+----
| 5 | 0 | 0 | 1 | 0 | 0 | 0 | 0 |
-----+---+---+---+---+---+---+----
| 6 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
-----+---+---+---+---+---+---+----
| 7 | 1 | 0 | 0 | 0 | 0 | 1 | 0 |
----------------------------------
It would be great if you helped me with this problem. Thank you very much!
Assuming that rows represent TRANSPORT_FROM and columns represent TRANSPORT_TO(because that seems to be what you meant), try:
SELECT A.TRANSPORT_FROM,
MAX(CASE WHEN TRANSPORT_TO = 1 THEN 1 ELSE 0 END) AS TO_1,
MAX(CASE WHEN TRANSPORT_TO = 2 THEN 1 ELSE 0 END) AS TO_2,
MAX(CASE WHEN TRANSPORT_TO = 3 THEN 1 ELSE 0 END) AS TO_3,
MAX(CASE WHEN TRANSPORT_TO = 4 THEN 1 ELSE 0 END) AS TO_4,
MAX(CASE WHEN TRANSPORT_TO = 5 THEN 1 ELSE 0 END) AS TO_5,
MAX(CASE WHEN TRANSPORT_TO = 6 THEN 1 ELSE 0 END) AS TO_6,
MAX(CASE WHEN TRANSPORT_TO = 7 THEN 1 ELSE 0 END) AS TO_7
FROM
(SELECT DISTINCT TRANSPORT_FROM FROM TRANSPORT_TABLE UNION SELECT DISTINCT TRANSPORT_TO FROM TRANSPORT_TABLE) A
LEFT JOIN
TRANSPORT_TABLE B
ON A.TRANSPORT_FROM = B.TRANSPORT_FROM
GROUP BY A.TRANSPORT_FROM;
I have done a UNION in an inner query to fill for the missing IDs(2 and 6) for the TRANSPORT_FROM. You could also do this by creating a dummy table containing all TRANSPORT_FROM IDs and using that table in place of that inner query represented by the alias A.
EDIT To make it dynamic.
I am not sure if this will work but I have tried a version that should at least give a direction.
SELECT
GROUP_CONCAT(
CONCAT(
' MAX(CASE WHEN TRANSPORT_TO = ',
t.TRANSPORT_TO,
' THEN 1 ELSE 0 END) AS TO_',
t.TRANSPORT_TO
)
) INTO #PivotQuery
FROM
(SELECT TRANSPORT_TO FROM TRANSPORT_TABLE GROUP BY TRANSPORT_TO) t;
SET #PivotQuery = CONCAT('SELECT TRANSPORT_FROM,', #PivotQuery, ' FROM TRANSPORT_TABLE GROUP BY TRANSPORT_FROM ORDER BY TRANSPORT_FROM');
PREPARE statement FROM #PivotQuery;
EXECUTE statement;
DEALLOCATE PREPARE statement;

Mysql table joins using a where clause

I am trying to run a MySQL query against a database and join 3 tables together.
I have 3 tables in the database;
Table containing the important data
+----+-------+----------------------+
| id | name | value |
+----+-------+----------------------+
| 1 | data1 | First piece of data |
| 2 | data2 | Second piece of data |
| 3 | data3 | Third piece of data |
+----+-------+----------------------+
Table containing flag_id to flag_name
+----+-------+-------------+
| id | name | description |
+----+-------+-------------+
| 1 | flag1 | NULL |
| 2 | flag2 | NULL |
| 3 | flag3 | NULL |
| 4 | flag4 | NULL |
+----+-------+-------------+
Table containing the one-to-many data to flag mapping
+----+---------+--------+---------+
| id | type_id | status | data_id |
+----+---------+--------+---------+
| 1 | 1 | 0 | 1 |
| 2 | 2 | 0 | 1 |
| 3 | 4 | 1 | 1 |
| 4 | 2 | 0 | 2 |
| 5 | 3 | 0 | 2 |
| 6 | 4 | 1 | 2 |
| 7 | 3 | 0 | 3 |
| 8 | 4 | 1 | 3 |
+----+---------+--------+---------+
I want to be able to have a single query that will show me each named flag as a column for each piece of data. In searching the web, I found an example doing it using this query:
select d.id, d.name, d.value,
MAX(CASE WHEN f.type_id = 1 THEN f.status ELSE NULL END) as flag1,
MAX(CASE WHEN f.type_id = 2 THEN f.status ELSE NULL END) as flag2,
MAX(CASE WHEN f.type_id = 3 THEN f.status ELSE NULL END) as flag3,
MAX(CASE WHEN f.type_id = 4 THEN f.status ELSE NULL END) as flag4
from data d
inner join flags f on f.data_id = d.id
group by d.id
Which gives the result I want.
+----+-------+----------------------+-------+-------+-------+-------+
| id | name | value | flag1 | flag2 | flag3 | flag4 |
+----+-------+----------------------+-------+-------+-------+-------+
| 1 | data1 | First piece of data | 0 | 0 | NULL | 1 |
| 2 | data2 | Second piece of data | NULL | 0 | 0 | 1 |
| 3 | data3 | Third piece of data | NULL | NULL | 0 | 1 |
+----+-------+----------------------+-------+-------+-------+-------+
The problem is that I need to add a where clause to filter on specific flags, but I get the error that 'flag4' is an Unknown column, which is because an alias cannot be used in a where clause.
How do I accomplish this, preferably in a single query that I can use with a 'where' clause?
Instead of use where, use having.
The flag columns are the result of an aggregating operation, so, if you want to apply a selection criteria on them, you have to use having. Example:
select d.id, d.name, d.value,
MAX(CASE WHEN f.type_id = 1 THEN f.status ELSE NULL END) as flag1,
MAX(CASE WHEN f.type_id = 2 THEN f.status ELSE NULL END) as flag2,
MAX(CASE WHEN f.type_id = 3 THEN f.status ELSE NULL END) as flag3,
MAX(CASE WHEN f.type_id = 4 THEN f.status ELSE NULL END) as flag4
from data d
inner join flags f on f.data_id = d.id
group by d.id
havig flag1 = 0

Group by historical date for each date in the provided range

Am stuck with this for days. wanna group a sql result set by historical dates. so want a result to be grouped by date from each date in the date specified range all the way back in time. Here is my sql so far, but it groups the result by date instead of historical date.
Please help!
SELECT ledger.transdate,
sum(case when transcodes.dtcr = 'C' then ledger.amount else 0 end) Credit,
sum(case when transcodes.dtcr = 'D' then ledger.amount else 0 end) Debit,
sum(case when transcodes.dtcr = 'C' then ledger.amount else 0 end) -
sum(case when transcodes.dtcr = 'D' then ledger.amount else 0 end) Balance
FROM
LEDGER
INNER JOIN TRANSCODES ON (LEDGER.TRANSCODE = TRANSCODES.TRANSCODE)
where ledger.transdate >= '2013-02-28' and ledger.transdate <= '2013-03-01'
group by ledger.transdate
Maybe consider this example...
SELECT * FROM ints;
+---+
| i |
+---+
| 0 |
| 1 |
| 2 |
| 3 |
| 4 |
| 5 |
| 6 |
| 7 |
| 8 |
| 9 |
+---+
SELECT x.i, SUM(y.i) running FROM ints x JOIN ints y ON y.i <= x.i GROUP BY i;
+---+---------+
| i | running |
+---+---------+
| 0 | 0 |
| 1 | 1 |
| 2 | 3 |
| 3 | 6 |
| 4 | 10 |
| 5 | 15 |
| 6 | 21 |
| 7 | 28 |
| 8 | 36 |
| 9 | 45 |
+---+---------+
If I understood you correctly, and you want to group by date-only part of transdate field, you can use Date() function, i.e. ... group by Date(transdate)
Your answer can be found here:
http://www.codeproject.com/Articles/300785/Calculating-simple-running-totals-in-SQL-Server