+----+--------+------+------------+-----------+----------+------+
| 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.
Related
I have a table called battery_data,
+-------+-------+-------+-------+-------+-------+-------+
|Module |Machine| Num1 | Num3 | Field | Value | Value2 |
+-------+-------+-------+-------+-------+-------+-------+
| T-01 | A&B | 23.9| 123 | Cell| POS | 328.34|
| T-01 | A&B | 27.0| 456 |Battery| POS | 23.8|
| T-01 | C&D | 409.01| 789 | EV | NEG | NULL |
| T-01 | C&D | 411.02| 124 | Cell | VSB | NULL |
| T-02 | A&B | 509.01| 989 | EV | NEG | NULL |
| T-02 | A&B | 611.02| 824 |Battery| VSB | NULL |
+-------+-------+-------+-------+-------+-------+-------+
I want an output which returns the occurrences of all POS/NEG/VSB in Value field aggregated per unique module and unique machine. (There are only 2 types of machine: A&B, C&D)
If a certain Value(POS/NEG/VSB) isn't found for a module, 0 should be returned for that column.
I want to generate an output table as,
+-------+-------+-------+-------+-------+
|Module |Machine| POS | NEG | VSB |
+-------+-------+-------+-------+-------+
| T-01 | A&B | 2 | 0 | 0 |
| T-01 | C&D | 0 | 1 | 1 |
| T-02 | A&B | 0 | 1 | 1 |
+-------+-------+-------+-------+-------+
What should be the SQL query to achieve this?
Well, as you say, you want to find "the occurrences of all POS/NEG/VSB in Value field aggregated per unique module and unique machine". So first, you have to group by module and machine, and then for each row you have to count if it's value is POS or NEG or VSB. One way to do that is to have a different counter for every possible value, and then increase the counter that corresponds to the value of the current row. One way of doing that is the following:
SELECT Module, Machine,
SUM(CASE WHEN Value = 'POS' THEN 1 ELSE 0 END) AS POS,
SUM(CASE WHEN Value = 'NEG' THEN 1 ELSE 0 END) AS NEG,
SUM(CASE WHEN Value = 'VSB' THEN 1 ELSE 0 END) AS VSB
FROM battery_data
GROUP BY Module, Machine
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.
I have this table and its data
----------------------------
| ID | NAME | TYPE | VALUE |
----------------------------
| 1 | A | YES | 10000 |
| 2 | B | NO | 100 |
| 3 | A | NO | 300 |
----------------------------
I wonder how to get data in sql like this :
-----------------------------
| ID | NAME | YES | NO |
-----------------------------
| 1 | A | 10000 | 300 |
| 2 | B | NULL | 100 |
-----------------------------
Please help
You need to pivot the data to do that.
select MIN(ID) as ID, NAME ,
Max(Case when TYPE = 'Yes' then VALUE END) as `Yes`
Max(Case when TYPE = 'No' then VALUE END) as `No`
From Yourtable
Group by NAME
Note: This assumes there are only two possible values(Yes&No) present in TYPE column.
Consider following table:
+------------+-----------+-------------+---------+------------+--------+-------------+
| client_id | TradeDate | servicetype | SEGMENT | OrdChannel | orders | OrderAmount |
+------------+-----------+-------------+---------+------------+--------+-------------+
| 1 | 20140611 | Type_1 | CASH | TT | 1 | 39275 |
| 2 | 20150119 | Type_1 | CASH | DNT | 2 | 11856.9 |
| 3 | 20150922 | Type_1 | FNO | OTHER | 1 | 854750 |
| 4 | 20151223 | Type_1 | CASH | TT | 5 | 71075 |
| 5 | 20140529 | Type_1 | Offline | FNO | 1 | 0 |
| 6 | 20160310 | Type_2 | CASH | WEB | 2 | 8009.6 |
| 7 | 20150318 | Type_1 | Offline | FNO | 2 | 432900 |
| 8 | 20150914 | Type_2 | CASH | WEB | 2 | 15612 |
| 9 | 20160317 | Type_2 | FNO | MINI | 1 | 9000 |
| 10 | 20140421 | Type_1 | CASH | TT | 8 | 17112.5 |
+------------+-----------+-------------+---------+------------+--------+-------------+
I am trying to group this data by client_id and TradeDate. Thus final dataset would contain each row for every <client-id, TradeDate> pair.
I want to compute following features from this data:
For each type of SEGMENT in every pair, I want to compute sum of orders and OrderAmount
Similarly, for each type of OrdChannel in every pair, I want to compute sum of orders and OrderAmount
Finally, a count of each servicetype i.e. Type_1 and Type_2.
Thus final dataset would contain columns similar to shown below:
+------------+-----------+-------------+---------+------------+--------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+
| client_id | TradeDate | SEGMENT_CASH_orders_sum | SEGMENT_CASH_OrderAmount_sum.... | OrdChannel_TT_orders_sum | OrdChannel_TT_OrderAmount_sum.... | servicetype_Type_1_count | servicetype_Type_2_count |
+------------+-----------+-------------+---------+------------+--------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+
So far, I have tried:
select clientsrno, TradeDate, SEGMENT, COUNT(orders) from orders group by clientsrno, TradeDate, SEGMENT;
but it's not giving separate columns for SEGMENT_CASH-orders_sum, etc.
Instead the output I am getting is:
+------------+-----------+---------+---------------+
| clientsrno | TradeDate | SEGMENT | COUNT(orders) |
+------------+-----------+---------+---------------+
| 44 | 20141209 | CASH | 23 |
| 44 | 20141211 | FNO | 10 |
+------------+-----------+---------+---------------+
You can do with a lot of sum( CASE .... END)
this is a suggestionfor the firts column
select client_di, TradeDate
sum (case SEGMENT
when 'CASH' then orders ELSE 0 END) as SEGMENT_CASH_orders_sum,
sum (case SEGMENT
when 'CASH' then OrderAmount ELSE 0 END) as SEGMENT_CASH_ordersAmount_sum,
sum (case SEGMENT
when 'FNO' then orders ELSE 0 END) as SEGMENT_FNO_orders,
sum (case SEGMENT
when 'FNO' then OrderAmount ELSE 0 END) as SEGMENT_FNO_ordersAmount_sum
from my_table
group by client_id, TradeDate
You can do for example:
SELECT clientsrno, TradeDate, SEGMENT, COUNT(orders), sumOrders.total FROM tabletest
INNER JOIN (
SELECT tabletest.tradeDate, SUM(orders) as total FROM tabletest
GROUP BY clientsrno, TradeDate, SEGMENT
) sumOrders ON tableTest.tradeDate = sumOrders.tradeDate
GROUP BY clientsrno, TradeDate, SEGMENT
And repeat the process for every sum you need.
I do not really know if this is possible to do this but I will expose my problem.
I have two tables cases and progress
cases
+----------+--------------+---------------------+---------+------+
| id_cases | name | date_surgery | archive | done |
+----------+--------------+---------------------+---------+------+
| 1 | Cranioplasty | 2016-02-01 00:00:00 | 1 | 0 |
| 2 | Cranioplasty | 2016-02-02 00:00:00 | 0 | 0 |
| 3 | Other | 2016-02-03 00:00:00 | 0 | 0 |
| 4 | Osteotomy | 2016-02-04 00:00:00 | 0 | 0 |
| 5 | Bone Tumor | 2016-02-05 00:00:00 | 1 | 1 |
+----------+--------------+---------------------+---------+------+
progress (which contains thousands of records)
+-------------+---------+---------+---------+
| id_progress | task_id | case_id | current |
+-------------+---------+---------+---------+
| 1 | 103006 | 1 | 0 |
| 2 | 103002 | 1 | 1 |
| 3 | 103003 | 1 | 1 |
| 4 | 201006 | 5 | 0 |
| 5 | 201007 | 5 | 1 |
| .... | ... | ... | ...|
+-------------+---------+---------+---------+
The link between the tables is cases.id_cases = progress.case_id
I want to select all cases with archive and done = 0. I also want to get some progress that are linked to this case
I tought about a condition to select a specific range of task_id related to the result of cases.name.
So basically I want this
SELECT id_cases, name, date_surgery, task_id, current
FROM cases
LEFT JOIN progress on progress.case_id = cases.id_cases
WHERE archive = 0 AND done = 0
But if name is Cranioplasty I just want progress.task_id that are equal to 103006, 103002 and 105002. For Bone Tumor I want 201006, 205003 and 207001. And this for each different name.
There is no logic between the id_cases and the task_id. I must hardcode this.
I tried differents things but none suceeded
SELECT id_Cases, name, date_surgery, task_id, current
from cases
left join progress on progress.case_id = cases.id_cases
where archive = 0 and done = 0
and case when name='Cranioplasty' then task_id=103006 and task_id=103002 else
case when name='Bone Tumor' then task_id=201006 else
case when name='Osteotomy' then task_id=301002 else
case when name='MBIO' then task_id=401006 end end end end
order by name, date_surgery
In fine I try to get this result (task_id is not important, I just want to result of current)
+------+--------------+-----------+--------+-------+--------+-------+--------+-------+
| case | name | date_surg | task_1 | 1_res | task_2 | 2_res | task_3 | 3_res |
+------+--------------+-----------+--------+-------+--------+-------+--------+-------+
| 1 | Cranioplasty | date | 103006 | 0 | 103002 | 0 | 105002 | 1 |
| 1 | Cranioplasty | date | 103006 | 1 | 103002 | 1 | 105002 | 0 |
| 1 | Cranioplasty | date | 103006 | 1 | 103002 | 0 | 105002 | 1 |
| 2 | Cranioplasty | date | 103006 | 0 | 103002 | 1 | 105002 | 0 |
| 2 | Cranioplasty | date | 103006 | 1 | 103002 | 0 | 105002 | 1 |
| 2 | Cranioplasty | date | 103006 | 0 | 103002 | 1 | 105002 | 1 |
| 3 | Bone Tumor | date | 201006 | 1 | 205003 | 0 | 205005 | 0 |
| 3 | Bone Tumor | date | 201006 | 0 | 205003 | 1 | 205005 | 1 |
| ... | | | | | | | | |
+------+--------------+-----------+--------+-------+--------+-------+--------+-------+
PS : I just put my table as an example to help understanding the problem. It does not includes all the records
I know that I can use temporary or virtual table but I wanted to know how to resolve this with only a query
Well, anyway its bad practice to hardcode this relations between name and task id. You need to store them in database or smthng. So you can join that table and do it in 1 query.
If you cant or dont want to its better to save them atleast to an array so you can dynamically generate query part with this conditions if its possible.
select
a.id_cases,
a.name,
b.task_id,
b.current
from
cases a
left join
progress b ON b.case_id = a.id_cases
where
a.archive = 0
and a.done = 0
and (
(b.task_id in (103006,103002,105002) and a.name = 'Cranioplasty')
OR (b.task_id in (201006,205003,207001) and a.name = 'Bone Tumor')
)
If you can use any language to generate this part
and (
(b.task_id in (103006,103002,105002) and a.name = 'Cranioplasty')
OR (b.task_id in (201006,205003,207001) and a.name = 'Bone Tumor')
)
Do it. For example in php
foreach($arRealtions as $name => $taskIDs)
{
$query .= '(b.task_id in ('.implode(',',$taskIDs).') and a.name = "'.$name.'")';
}