Looking for a solution to group and count. I have a working SQL which counts open records per value:
SELECT tech_query.assigned_to_group, COUNT(tech_query.assigned_to_group) AS qty
FROM tech_query
WHERE tech_query.status <> 9
AND tech_query.status <> 3
GROUP BY tech_query.assigned_to_group
ORDER BY tech_query.assigned_to_group
The outcome:
Name: | qty
-----------------------
ME-MS | 5
MU-TA-AAA | 4
MU-TA-BBB | 2
MU-TA-CCC | 3
Now I also like to combine the Name data which begins with MU%, sum the data of this value MU% and get an outcome as follows:
Name: | qty
-----------------------
ME-MS | 5
MU | 9
Curious if somebody can help :-)
You need contional for mu like. try this query:
SELECT (case when tech_query.assigned_to_group like "MU%" then "MU"
else tech_query.assigned_to_group end) as Name,
COUNT(tech_query.assigned_to_group) AS qty
FROM tech_query
WHERE tech_query.status <> 9
AND tech_query.status <> 3
GROUP BY name
ORDER BY name
Use a derived table to extract MU part when required:
SELECT name, COUNT(*) AS qty
FROM
(select case when tech_query.assigned_to_group like 'MU%' then 'MU'
else tech_query.assigned_to_group end as name
from tech_query
WHERE tech_query.status <> 9
AND tech_query.status <> 3) dt
GROUP BY name
ORDER BY name
Note: When reading the other answer (Balinti's), I realize MySQL perhaps wants double quotes for string literals, instead of ANSI SQL's single quotes? So maybe you need to replace 'MU%' then 'MU' with "MU%" then "MU"?
Related
Evening all.
I am trying to create a very basic case statement which buckets three scenarios with a 0 or a 1 in mySQL.
I have three fields found in the reference table link below.
Essentially I am trying to bucket any ProductID that has a StatusCD of 'I' and 'O' as 1, only 'I' as 1 and then anything with only an 'O' result and no corresponding 'I' as a 0. What this data is showing is a product coming into the warehouse ('I') and then exiting the warehouse ('O'). I have other fields which are capturing date differences but ultimately I am trying to create a flag to ignore scenarios where we only have Product#'s with an 'O' statusCD which would indicate their arrival to the warehouse was not logged appropriately and would skew our "Age in warehouse" buckets.
Any insight is greatly appreciated!
Reference Table with fields:
Date | ProductID | StatusCD
2021-01-01 | U1000 | I
2021-01-10 | U1000 | O
2021-01-10 | U2000 | I
2021-01-15 | U3000 | O
Assuming you want to retain every original record, you could use analytic functions here:
SELECT Date, ProductID, StatusCD,
CASE WHEN SUM(StatusCD <> 'O') OVER (PARTITION BY ProductID) = 0
THEN 0 ELSE 1 END As Label
FROM yourTable
ORDER BY Date;
Demo
For versions of MySQL earlier than 8+:
SELECT t1.Date, t1.ProductID, t1.StatusCD,
CASE WHEN t2.OpenCount = 0 THEN 0 ELSE 1 END AS Label
FROM yourTable t1
INNER JOIN
(
SELECT ProductID, SUM(StatusCD <> 'O') AS OpenCount
FROM yourTable
GROUP BY ProductID
) t2
ON t2.ProductID = t1.ProductID
ORDER BY
t1.Date;
Demo
I have a table that contains id and country name, and I need to convert them so the id with more than 1 country will display in 1 row.I have been searching in this forum for over an hour and found nothing.
I tried if using the pivot function can help me to achieve the result i wanted, but I feel like using pivot does not work on my case here.
This is a mini version of the table I have. The number of distinct value in the field "country" will be over 100, so I can just say something like when county = '..' as this will be to repetitive.
enter code here
+----+--------+
| id | country|
+----+--------+
| 1 | US |
| 1 | UK |
| 2 | JP |
+----+--------+
Desired outcome I am looking for:
enter code here
+----+-----------+-----------+
| id | country_1 | country_2 |
+----+-----------+-----------+
| 1 | US | UK |
| 2 | JP | null |
+----+-----------+-----------+
I found this question which is similar but it is the opposite of what I am trying to achieve.
MySQL statement to pivot table without using pivot function or a union
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
update:
Thank you so much for all of your helps. I may not have used the queries of yours to solve my problem - as of the fact that the syntax is a bit diff running in snowflake. However, I got the insights I need from all of you.
here is my solution:
enter code here
select t1.id,
max(iff(t1.row_number = 1, t1.country ,null)) as country_1,
max(iff(t1.row_number = 2, t1.country ,null)) as country_2,
max(iff(t1.row_number = 3, t1.country, null)) as country_3
from
(
select id, country, row_number() over (partition by id order by id ) as
row_number
from table
) t1
group by t1.id
Whereas you could do it with "pivoting", what will happen when you have 3 countries? Or 4? Or 17?
May I suggest this:
SELECT id,
GROUP_CONCAT(country)
FROM tbl
GROUP BY id;
You will get something like:
1 US,UK
2 JP
use aggregation
select id, max(case when id=1 then country end ) as country_1,
max(case when id=2 then country end ) as country_2
from tbale group by id
As you comment on #Rick answer you have max 3 country for each id then you can use this
select
id,
(select country from test where test.id=t.id limit 0,1)as country_1,
(select country from test where test.id=t.id limit 1,1)as country_2,
(select country from test where test.id=t.id limit 2,1)as country_3
from test as t
group by id;
DEMO
You can try this following script with RowNumber generated per id. As you confirmed there are maximum 3 country per id, we can easily generate your desired result set by handling RowNumber 1,2 & 3
SELECT ID,
MAX(CASE WHEN RowNumber = 1 THEN country ELSE NULL END) Country_1,
MAX(CASE WHEN RowNumber = 2 THEN country ELSE NULL END) Country_2,
MAX(CASE WHEN RowNumber = 3 THEN country ELSE NULL END) Country_3
FROM
(
SELECT id,
country,
#row_num :=IF(#prev_value = concat_ws('',id),#row_num+1,1)AS RowNumber
,#prev_value := concat_ws('',id)
FROM tbale
ORDER BY id
)A
GROUP BY id
There's no "dynamic" PIVOT in SQL. You need to specify the list of columns when writing the query. Your options are:
If you know the number of columns in advance, then #ZaynulAbadinTuhin solution is the easier. It seems, however, this is not your case.
If you don't know the number of columns in advance and you want them all concatenated in a single column, then #Rick James solution is the best.
Otherwise, you can still use some kind of dynamic SQL in your app or in a stored procedure that will build the SQL query at runtime, based on the existing values of the table. But this solution would require much more programming. It's not a single/simple SQL query anymore. See Rick James's Pivoting in MySQL stored procedure.
After some research I haven't found what I need and I thought I'll ask here. I'm currently trying to develop a advanced search mode for a application and I'm stuck with my task. Maybe you can help me. So imagine I have the following table:
ID | Name | Surname
1 | John | Mim
2 | Johnny | Crazy
3 | Mike | Something
4 | Milk | Milk
5 | Peter | IDontknow
6 | Mitch | SomeName
Then in my frontend, there's one input field. The input of that field will go trough the query in that way:
SELECT name, surname FROM people WHERE name LIKE 'input%' OR surname LIKE 'input%'
Now lets say my input is "Mi", so I'll have 3 columns match in the "name" column, and 2 in the surname. And that's what I'm looking for.
A count which ouputs the following:
Column | Count
Name | 3
Surname | 2
Is there a way to achieve this in only one query?
What I've tried so far:
I actually created the table above on my localhost in my database and tried different queries. Tried with SELECT count(name), count(surname), but that would output 3 for both counts. So I'm not even sure if that's possible in only one query.
use union all
SELECT 'name' as col, count(name) as cnt FROM people WHERE name LIKE 'input%'
union all
SELECT 'surname', count(surname) FROM people WHERE surname LIKE 'input%'
make customize group using case when
SELECT (case when name LIKE 'input%' then 'name'
else 'surname' end) as Column, count(*) as cnt
FROM people WHERE name LIKE 'input%' OR surname LIKE 'input%'
group by Column
Try this:
SELECT "Name" as Column, count(*) as Count FROM people WHERE name LIKE 'mi%'
UNION
SELECT "Surname" as Column, count(*) as Count FROM people WHERE surname LIKE 'mi%'
In Mysql booleans are evaluated as 1 or 0, so you can do this:
select 'Name' Column, sum(name LIKE 'input%') Count from people
union all
select 'Surname', sum(surname LIKE 'input%') from people
For Mysql 8.0+ you can avoid the double scan of the table with a CTE:
with cte as (
select
sum(name LIKE 'input%') namecounter,
sum(surname LIKE 'input%') surnamecounter
from people
)
select 'Name' Column, namecounter Count from cte
union all
select 'Surname', surnamecounter from cte
The solution without UNION[ ALL] of the people table:
SELECT
CASE cj.x WHEN 1 THEN 'Name' ELSE 'Surname' END AS `Column`,
CASE cj.x
WHEN 1 THEN COUNT(CASE WHEN Name LIKE concat(#input, '%') THEN 1 end)
ELSE COUNT(CASE WHEN Surname LIKE concat(#input, '%') THEN 1 END)
END `Count`
FROM people CROSS JOIN (SELECT 1 AS x UNION ALL SELECT 2) AS cj
WHERE Name LIKE concat(#input, '%') OR Surname LIKE concat(#input, '%')
GROUP BY cj.x;
Output for the Mi input:
| Column | Count |
+---------+-------+
| Name | 3 |
| Surname | 2 |
Test it online with SQL Fiddle.
I have a table like this :
Type | Time
1 | 234234
2 | 234235
1 | 234238
3 | 234239
4 | 234240
1 | 234242
2 | 234245
I want to count number of all those rows where type=1 and next row's type=2.
For ex : The result here is 2.
I don't know how to put where clause on next row.
You should be able to implement user defined variables to get the total:
select count(*) Total
from
(
select type,
#row:=(case when #prev=1 and type=2 then 'Y' else 'N' end) as Seq,
#prev:=type
from yourtable, (SELECT #row:=null, #prev:=null) r
order by time, type
) src
where Seq = 'Y'
See SQL Fiddle with Demo
I have table like this:
+----+---------+---------+--------+
| id | value_x | created | amount |
+----+---------+---------+--------+
value_x is set of six strings, lets say "one", "two", "three", etc.
I need to create report like this:
+--------------+-------------------------+-------------------+----------------------+
| day_of_month | "one" | "two" | [etc.] |
+--------------+-------------------------+-------------------+----------------------+
| 01-01-2011 | "sum(amount) where value_x = colum name" for this specific day |
+--------------+-------------------------+-------------------+----------------------+
Most obvious solution is:
SELECT SUM(amount), DATE(created) FROM `table_name` WHERE value_x=$some_variable GROUP BY DATE(created)
And loop this query six times with another value for $some_variable in every iteration, but I'm courious if is it possible to do this in single query?
What you're asking is called a "pivot table" and is typically achieved as below. The idea is for each potential value of value_x you either produce a 1 or 0 per row and sum 1's and 0's to get the sum for each value.
SELECT
DATE(created),
SUM(CASE WHEN value_x = 'one' THEN SUM(amount) ELSE 0 END) AS 'one',
SUM(CASE WHEN value_x = 'one' THEN SUM(amount) ELSE 0 END) AS 'two',
SUM(CASE WHEN value_x = 'one' THEN SUM(amount) ELSE 0 END) AS 'three',
etc...
FROM table_name
GROUP BY YEAR(created), MONTH(created), DAY(created)
This will come close:
SELECT
s.day_of_month
,GROUP_CONCAT(CONCAT(s.value_x,':',s.amount) ORDER BY s.value_x ASC) as output
FROM (
SELECT DATE(created) as day_of_month
,value_x
,SUM(amount) as amount
FROM table1
GROUP BY day_of_month, value_x
) s
GROUP BY s.day_of_month
You will need to read the output and look for the value_x prior to the : to place the items in the proper column.
The benefit of this approach over #Michael's approach is that you do not need to know the possible values of field value_x beforehand.