MySQL CASE working backwards - mysql

I'm using CASE to clean up some state abbreviations, in a table, but it's working contrary to the logic. I selected the length alone to show that the length is being calculated correctly, so I think it's the CASE logic that's off
When I query...
SELECT billing_state,
length(billing_state),
CASE billing_state
WHEN length(billing_state) > 2 THEN (select state_abbr from lkup_states where upper(state_name) = billing_state)
WHEN length(billing_state) = 2 THEN upper(billing_state)
ELSE 'UNKNOWN'
END as billing_state_fixed
FROM accounts
+---------------+-----------------------+---------------------+
| billing_state | length(billing_state) | billing_state_fixed |
+---------------+-----------------------+---------------------+
| GA | 2 | NULL |
| Alabama | 7 | ALABAMA |
| MS | 2 | NULL |
| FL | 2 | NULL |
| NULL | NULL | UNKNOWN |
+---------------+-----------------------+---------------------+
However, when I enter this bizarro logic, it works.
SELECT billing_state,
length(billing_state),
CASE billing_state
WHEN length(billing_state) = 2 THEN (select state_abbr from lkup_states where upper(state_name) = billing_state)
WHEN length(billing_state) <> 2 THEN upper(billing_state)
ELSE 'UNKNOWN'
END as billing_state_fixed
FROM accounts
+---------------+-----------------------+---------------------+
| billing_state | length(billing_state) | billing_state_fixed |
+---------------+-----------------------+---------------------+
| GA | 2 | GA |
| Alabama | 7 | AL |
| MS | 2 | MS |
| FL | 2 | FL |
| NULL | NULL | UNKNOWN |
+---------------+-----------------------+---------------------+
Can anyone take a swing at this one?

Per the docs, your syntax isn't quite correct.
You've muddle CASE value WHEN compare_value and CASE WHEN expression.
What you probably want is:
SELECT billing_state,
length(billing_state),
CASE
WHEN length(billing_state) > 2 THEN (select state_abbr from lkup_states where upper(state_name) = billing_state)
WHEN length(billing_state) = 2 THEN upper(billing_state)
ELSE 'UNKNOWN'
END as billing_state_fixed
FROM accounts

Related

Find min value in column by grouping more than one column in sql

+----+-------+-----------------------------+-------------------------+-------------------+-------------+
| Id | grade | shot_name | submitted_by_supervisor | version_submitted | submit_type |
+----+-------+-----------------------------+-------------------------+-------------------+-------------+
| 27 | A | elx_reel01_scn1020_shot1720 | Salil Devji | 33 | Fresh |
| 27 | A | elx_reel01_scn1020_shot1720 | Deepali | 34 | Fresh |
| 37 | A | elx_reel01_scn1030_shot3480 | Salil Devji | 15 | Fresh |
| 37 | A | elx_reel01_scn1030_shot3480 | Salil Devji | 20 | Fresh |
| 7 | B | elx_reel01_scn1010_shot1030 | Darshan | 4 | Fresh |
| 7 | B | elx_reel01_scn1010_shot1030 | Varion | 6 | Fresh |
| 17 | B | elx_reel01_scn1010_shot1140 | Varion | 17 | Fresh |
| 17 | B | elx_reel01_scn1010_shot1140 | Varion | 14 | Fresh |
+----+-------+-----------------------------+-------------------------+-------------------+-------------+
I have column (submit_type) inserting new column in that value are set by CASE condition
here is my sql query :
SELECT s.shot_id,
s.shot_name ,
isn.reviewer AS 'submitted_by_supervisor',
isn.version AS 'version_submitted',
isn.grade AS 'grade',
CASE
WHEN isn.version = Min(isn.version) THEN 'FRESH'
ELSE 'Once Submitted'
end AS 'submit_type'
FROM viewd_elx.india_supe_note isn
JOIN viewd_elx.shot s
ON s.shot_id = isn.shot_id
JOIN viewd_elx.team t
ON isn.shot_id = t.shot_id
JOIN viewd_elx.viewd_team vt
ON isn.shot_id = vt.shot_id
WHERE isn.promoted='Yes'
AND isn.grade IN ('A',
'B')
GROUP BY isn.grade,
s.shot_id,
isn.version;
mentioned query gives 'Fresh' value in all field in (submit_type) column. which is not correct.
What I need exactly is, I am grouping column and finding MIN(value) of column,
Work Flow: -
grade A => group (shot_name) => min(version_submited) => set 'Fresh' else 'Once submitted' in (submit_type)
In Grade 'A' have same shot_name, grouping this (shot_name) and then finding min(version_submited) if min value found then set 'fresh' else set 'once submitted' value in (submit_type) column.
Also for Grade B like Grade A.
I need result like this =>
+----+-------+-----------------------------+-------------------------+-------------------+----------------+
| Id | grade | shot_name | submitted_by_supervisor | version_submitted | submit_type |
+----+-------+-----------------------------+-------------------------+-------------------+----------------+
| 27 | A | elx_reel01_scn1020_shot1720 | Salil Devji | 33 | Fresh |
| 27 | A | elx_reel01_scn1020_shot1720 | Deepali | 34 | Once Submitted |
| 37 | A | elx_reel01_scn1030_shot3480 | Salil Devji | 15 | Fresh |
| 37 | A | elx_reel01_scn1030_shot3480 | Salil Devji | 20 | Once Submitted |
| 7 | B | elx_reel01_scn1010_shot1030 | Darshan | 4 | Fresh |
| 7 | B | elx_reel01_scn1010_shot1030 | Varion | 6 | Once Submitted |
| 17 | B | elx_reel01_scn1010_shot1140 | Varion | 17 | Once Submitted |
| 17 | B | elx_reel01_scn1010_shot1140 | Varion | 14 | Fresh |
+----+-------+-----------------------------+-------------------------+-------------------+----------------+
The issue here is that you are grouping by on isn.version field as well, and trying to compute the minimum of the same field in that group. It will simply return the same value, and that is why all are coming as "Fresh". You will need to determine the minimum isn.version value for a group of (grade, shot_id) separately in a subquery (Derived Table), and then use that to check whether minimum or not.
SELECT s.shot_id,
s.shot_name ,
isn.reviewer AS submitted_by_supervisor,
isn.version AS version_submitted,
isn.grade AS grade,
CASE
WHEN isn.version = dt.min_version THEN 'FRESH'
ELSE 'Once Submitted'
END AS 'submit_type'
FROM viewd_elx.india_supe_note isn
JOIN viewd_elx.shot s
ON s.shot_id = isn.shot_id
JOIN viewd_elx.team t
ON isn.shot_id = t.shot_id
JOIN viewd_elx.viewd_team vt
ON isn.shot_id = vt.shot_id
JOIN (
SELECT grade,
shot_id,
MIN(version) AS min_version
FROM viewd_elx.india_supe_note
WHERE promoted = 'YES'
AND grade IN ('A', 'B')
GROUP BY grade,
shot_id
) AS dt
ON dt.grade = isn.grade
AND dt.shot_id = isn.shot_id
WHERE isn.promoted='Yes'
AND isn.grade IN ('A','B')
GROUP BY s.shot_id,
s.shot_name,
isn.reviewer,
isn.version,
isn.grade,
dt.min_version

Mysql, Dynamic query for rows to column

I've three tables with name employee, employee_products, product_type
reference : http://sqlfiddle.com/#!9/00436/4
I'm trying to get data as
Let this table is Table_1
using this query:
select emp.name,
(select count(*) from employee_products where product_type_id = 1 and employee_id = emp.id) as Service,
(select count(*) from employee_products where product_type_id = 2 and employee_id = emp.id) as Product,
(select count(*) from employee_products where product_type_id = 3 and employee_id = emp.id) as Other
from employee as emp;
but, i think it is not efficient and from every new product_type_id i've to alter this query, can I do this dynamically.
+------------+---------+---------+-------+--+
| Name | Service | Product | Other | |
+------------+---------+---------+-------+--+
| Bezos | 1 | 0 | 0 | |
+------------+---------+---------+-------+--+
| Steve | 0 | 3 | 0 | |
+------------+---------+---------+-------+--+
| Bill gates | 1 | 0 | 0 | |
+------------+---------+---------+-------+--+
| Tim Cook | 0 | 0 | 1 | |
+------------+---------+---------+-------+--+
and
Let this table is Table_2
In this I can't figure out how this is even possible in mysql as there is no pivot feature in mysql.
+------------+---------+---------+---------+---------+-----------+-------+
| Name | Amazon | iPhone | iPad | iPod | Microsoft | IDK |
+------------+---------+---------+---------+---------+-----------+-------+
| Bezos | Service | NULL | NULL | NULL | NULL | NULL |
+------------+---------+---------+---------+---------+-----------+-------+
| Steve | NULL | Product | Product | Product | NULL | NULL |
+------------+---------+---------+---------+---------+-----------+-------+
| Bill gates | NULL | NULL | NULL | NULL | PRODUCT | NULL |
+------------+---------+---------+---------+---------+-----------+-------+
| Tim Cook | NULL | NULL | NULL | NULL | NULL | OTHER |
+------------+---------+---------+---------+---------+-----------+-------+
Please help.
Note : There can be more than 100 items in product_type, employee_products table.
Try this for Table_1
Select name, Max(Service) as Service, Max(Product) as Product, Max(Other) as Other
From (
select e.name,
count(case when ep.product_type_id = 1 then 1 else null end) as Service,
count(case when ep.product_type_id = 2 then 1 else null end) as Product,
count(case when ep.product_type_id = 3 then 1 else null end) as Other,
from employee e
inner join employee_products ep on (e.id = ep.employee_id)
)
Group by name;
Note: same way you can try for Table_2
There are several bits of code out there for dynamically building and running the SELECT with the columns dynamically deduced. Here is mine.

COUNT counting something on LEFT JOIN that doesn't exist. Why?

I'm having a problem.
I have this table called usersbycourse which shows this information:
+------------+-----------------+--------+-----------+-------+-----------------+-----------------+
| instanceid | shortname | userid | firstname | logid | lastaccessdelta | modulesfinished |
+------------+-----------------+--------+-----------+-------+-----------------+-----------------+
| 2 | PJU | 74 | Robin | 766 | 1662246 | 0 |
| 3 | Fundgest-GRHN1A | 75 | Batman | 867 | 1576725 | 0 |
| 3 | Fundgest-GRHN1A | 77 | Abigobeu | 1004 | 610480 | 0 |
+------------+-----------------+--------+-----------+-------+-----------------+-----------------+
and this SQL:
SELECT
mdl_course.id,
mdl_course.shortname,
COUNT(CASE WHEN usersbycourse.modulesfinished = 1 THEN NULL ELSE 1 END) AS studentcount
FROM mdl_course LEFT JOIN usersbycourse ON mdl_course.id = usersbycourse.instanceid
GROUP BY mdl_course.id;
The results from the SQL are:
+----+-----------------+--------------+
| id | shortname | studentcount |
+----+-----------------+--------------+
| 1 | Unity I | 1 |
| 2 | PJU | 1 |
| 3 | Fundgest-GRHN1A | 2 |
| 4 | asdzxc2 | 1 |
+----+-----------------+--------------+
But why? In inside SQL has no Unity I, and no asdzxc2. How do I produce a result like this:
+----+-----------------+--------------+
| id | shortname | studentcount |
+----+-----------------+--------------+
| 1 | Unity I | 0 |
| 2 | PJU | 1 |
| 3 | Fundgest-GRHN1A | 2 |
| 4 | asdzxc2 | 0 |
+----+-----------------+--------------+
?
EDIT:
I want to count only rows having modulesfinished = 0
What you're looking for is SUM rather than COUNT, that is,
SELECT
mdl_course.id,
mdl_course.shortname,
SUM(CASE WHEN usersbycourse.modulesfinished = 0 THEN 1 ELSE 0 END) AS studentcount
FROM mdl_course LEFT JOIN usersbycourse ON mdl_course.id = usersbycourse.instanceid
GROUP BY mdl_course.id;
The problem is because you are using LEFT JOIN some of the values for usersbycourse.modulesfinished are NULL
Something you need to learn is
NULL == something
Is always unknown, not true, not false, just unknown.
So when you try to compare with = 1 your nulls get the ELSE but not because they aren't 1, is because is all the rest.
So if instead you change the condition to
COUNT(CASE WHEN usersbycourse.modulesfinished = 0 THEN 1 ELSE NULL)
Only the TRUE match will get 1, the FALSE and the UNKNOW part ill get NULL and COUNT doesnt count nulls. And that is what you want.

Columns auto selecting

In my fluid structure I have this raw results:
+----------------------------------------------------------------------+
| Results |
+----+----------+-------------+----------+-----------+-----------------+
| id | group_id | question_id | question | answer_id | answer | input |
+----+----------+-------------+----------+-----------+-----------------+
| 1 | 10001 | 1 | How old | 1 | 25 | NULL |
| 2 | 10001 | 2 | What like| 3 | Cola | NULL |
| 3 | 10001 | 2 | What like| 4 | Other | HotDog |
| 4 | 10001 | 3 | City | 5 | NYC | NULL |
| 5 | 10001 | 4 | Name | 7 | Other | Alex |
| 6 | 10002 | 1 | How old | 1 | 25 | NULL |
| 7 | 10002 | 2 | What like| 6 | Candy | NULL |
| 8 | 10002 | 3 | City | 8 | LA | NULL |
| 9 | 10002 | 4 | Name | 7 | Other | Roman |
+----+----------+-------------+----------+-----------+--------+--------+
After transform:
SET #i := 1;
SELECT #i := #i + 1 AS `id`,
GROUP_CONCAT(CASE WHEN question = 'How old' THEN answer ELSE NULL END) AS `How Old`,
GROUP_CONCAT(CASE WHEN question = 'What like' THEN IF(answer='Other', input, answer) ELSE NULL END) AS `What like`,
GROUP_CONCAT(CASE WHEN question = 'City' THEN answer ELSE NULL END) AS `City`,
GROUP_CONCAT(CASE WHEN question = 'Name' THEN IF(answer='Other', input, NULL) ELSE NULL END) AS `Name`
FROM theTable
GROUP BY group_id;
I have this table:
+----+----------+-------------+----------+-----------+
| id | How Old | What like | City | Name |
+----+----------+-------------+----------+-----------+
| 1 | 25 | Cola,HotDog | NYC | Alex |
| 2 | 25 | Candy | LA | Roman |
+----+----------+-------------+----------+-----------+
It is example query, but real query with normal row ids link - works perfectly. But, i have different count of questions with some typical answer variant in other quiez.
What I can put switch of this rules:
GROUP_CONCAT(CASE WHEN question = 'How old' THEN answer ELSE NULL END) AS `How Old`,
GROUP_CONCAT(CASE WHEN question = 'What like' THEN IF(answer='Other', input, answer) ELSE NULL END) AS `What like`,
GROUP_CONCAT(CASE WHEN question = 'City' THEN answer ELSE NULL END) AS `City`,
GROUP_CONCAT(CASE WHEN question = 'Name' THEN IF(answer='Other', input, NULL) ELSE NULL END) AS `Name`
to MySQL cycle or procedure in top answer like as https://dba.stackexchange.com/questions/47902/how-to-transpose-convert-rows-as-columns-in-mysql?
p.s.
Also, I can prepare "select" in PHP, but its too simple =)

How create new columns according the groups in a table?

By using mysql can i create new columns according the groups in a table?i only can get the grouping and group_concat.
Before
-------------------------
no | item | code |
-------------------------
1 | aa | x |
2 | cc | c |
3 | pfr | a |
4 | bog | |
5 | aa | x |
6 | pfr | x |
1 | aa | x |
6 | pfr | a |
-------------------------
After group and group_concat
-------------------------
no | item | code |
-------------------------
1 | aa | x-2 |
2 | cc | c-1 |
3 | pfr | a-1 |
4 | bog | |
5 | aa | x-1 |
6 | pfr | a-1,x-1 |
-------------------------
I want to make like below this. Is it possible?
-------------------------------------------------------------------------------------
no | aa_qty | aa_code | cc_qty | cc_code | pfr_qty | pfr_code | bog_qty | bog_code |
-------------------------------------------------------------------------------------
1 | 2 | x-2 | | | | | | |
2 | | | 1 | c-1 | | | | |
3 | | | | | 1 | a-1 | | |
4 | | | | | | | 1 | |
5 | 1 | x-1 | | | | | | |
6 | | | | | 2 | a-1,x-1 | | |
-------------------------------------------------------------------------------------
You can achieve this using Pivot Table mechanism. MySQL does not have direct support on this mechanism. You need to depend on various if .. else.. or case .. when ... statements to build the required result view.
On the sample data given, say in table item_codes with no, item, and code as columns, you can try following example.
select no,
case item when 'aa' then cnt else '' end as aa_qty,
case item when 'aa' then code else '' end as aa_code,
case item when 'cc' then cnt else '' end as cc_qty,
case item when 'cc' then code else '' end as cc_code,
case item when 'pfr' then cnt else '' end as pfr_qty,
case item when 'pfr' then code else '' end as pfr_code,
case item when 'bog' then cnt else '' end as bog_qty,
case item when 'bog' then code else '' end as bog_code
from
(
select no, item, sum(cnt) cnt, group_concat( code ) code
from
(
select
no, item, count(no) cnt,
if( code='', code, concat( code, '-', count(no) ) ) 'code'
from item_codes ic
group by ic.no, ic.item, ic.code
) ig group by no, item
) grouped_data;
You may require some changes based on the data differences and other occurrences like null and empty codes, etc.