Columns auto selecting - mysql

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 =)

Related

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.

Sum and Display MySQL to PHP Table

+----+--------+------+------------+-----------+----------+------+
| id | deb_id | name | date | nominal | duration | type |
+----+--------+------+------------+-----------+----------+------+
| 1 | K7PJ8 | John | 2016-09-04 | 100000.00 | 2 | DB |
| 2 | K7PJ7 | Rey | 2016-08-30 | 125000.00 | 1 | DB |
| 3 | K7PJ8 | John | 2016-09-05 | 50000.00 | 2 | CR |
| 4 | K7PJ7 | Rey | 2016-08-05 | 25000.00 | 1 | CR |
+----+--------+------+------------+-----------+----------+------+
From the MySQL table above, it is possible if I want to display like the table below using PHP, and what syntax can I use for this ?
Result :
+--------+------+------------+------------+
| deb_id | name | nominal | residual |
+--------+------+------------+------------+
| K7PJ8 | John | 100000.00 | 50000.00 |
| K7PJ7 | Rey | 125000.00 | 100000.00 |
+--------+------+------------+------------+
Grouped by deb_id, and then sum the nominal WHERE type =(CR-DB)
SELECT deb_id
, name
, SUM(CASE WHEN type = 'DB' THEN nominal ELSE 0 END) AS nominal
, SUM(CASE WHEN type = 'CR' THEN nominal ELSE 0 END) AS credit
, SUM(CASE WHEN type = 'DB' THEN nominal ELSE 0 END) - SUM(CASE WHEN type = 'CR' THEN nominal ELSE 0 END) AS residual
FROM myTable
GROUP
BY deb_id
, name
You can you a case statement to separate those values into two separate columns.

How to sort results order by timestamp except one of them?

I have a table like this:
// Mytable
+----+--------------------+------+------------------+-----------+
| Id | QuestionOrAnswer | Type | AcceptedAnswerId | timestamp |
+----+--------------------+------+------------------+-----------+
| 1 | question1 | 0 | 3 | 1 |
| 2 | answer1 | 1 | NULL | 2 |
| 3 | answer2 | 1 | NULL | 3 | -- accepted answer
| 4 | answer3 | 1 | NULL | 4 |
+----+--------------------+------+------------------+-----------+
Now I want this result: (please focus on the order)
+----+--------------------+------+------------------+-----------+
| Id | QuestionOrAnswer | Type | AcceptedAnswerId | timestamp |
+----+--------------------+------+------------------+-----------+
| 1 | question1 | 0 | 3 | 1 |
| 3 | answer2 | 1 | NULL | 3 | -- accepted answer
| 2 | answer1 | 1 | NULL | 2 |
| 4 | answer3 | 1 | NULL | 4 |
+----+--------------------+------+------------------+-----------+
// ^ 0 means question and 1 means answer
Well how can I do that? (I want something exactly like SO sorting)
Here is my try:
SELECT * FROM Mytable WHERE 1 ORDER BY Type, {I need to add something here}, timestamp
You need to join the table to itself to determine which row is the accepted answer. Then the information can be used in the ORDER BY:
SELECT t.*
FROM Mytable t LEFT JOIN
Mytable tans
ON t.id = tans.AcceptedAnswerId
ORDER BY t.Type,
(tans.id IS NOT NULL) DESC,
t.timestamp

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.

MySQL CASE working backwards

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

Categories