MySQL - group by new column - mysql

I'm trying to group by a new columns here - one three counts.
It's a scenario where I want to see open, closed and plan orders for each date.
At the moment, with the code below I'm getting the results however I want to have a column with Main Date and count for each dates.
The results I am getting are as follows:
+------------+----------+------------+--------+------------+--------+
| Closed | ClosedNo | Open | OpenNo | Plan | PlanNo |
+------------+----------+------------+--------+------------+--------+
| NULL | 0 | NULL | 0 | 2018-10-22 | 3 |
| NULL | 0 | NULL | 0 | 2018-10-23 | 1 |
| NULL | 0 | NULL | 0 | 2018-10-24 | 1 |
| NULL | 0 | NULL | 0 | 2018-10-25 | 1 |
| NULL | 0 | 2018-10-25 | 1 | NULL | 0 |
| NULL | 0 | 2018-10-26 | 1 | NULL | 0 |
| NULL | 0 | 2018-10-27 | 2 | NULL | 0 |
| 2018-10-22 | 3 | NULL | 0 | NULL | 0 |
| 2018-10-23 | 1 | NULL | 0 | NULL | 0 |
| 2018-10-25 | 1 | NULL | 0 | NULL | 0 |
+------------+----------+------------+--------+------------+--------+
The desired results are:
Date ClosedNo OpenNo PlanNo
22/10/2018 3 3
23/10/2018 1 1
24/10/2018 1
25/10/2018 1 1 1
26/10/2018 1
27/10/2018 2
This is a code I use.
CREATE TABLE Orders
(Closed DATE,
Open DATE,
Plan DATE);
insert into Orders values ("2018-10-23",NULL,NULL);
insert into Orders values ("2018-10-22",NULL,NULL);
insert into Orders values ("2018-10-22",NULL,NULL);
insert into Orders values ("2018-10-22",NULL,NULL);
insert into Orders values (NULL,NULL,"2018-10-23");
insert into Orders values (NULL,NULL,"2018-10-22");
insert into Orders values (NULL,NULL,"2018-10-22");
insert into Orders values (NULL,NULL,"2018-10-22");
insert into Orders values (NULL,"2018-10-26",NULL);
insert into Orders values (NULL,"2018-10-27",NULL);
insert into Orders values (NULL,"2018-10-27",NULL);
insert into Orders values (NULL,"2018-10-25",NULL);
insert into Orders values (NULL,NULL,"2018-10-24");
insert into Orders values ("2018-10-25",NULL,NULL);
insert into Orders values (NULL,NULL,"2018-10-25");
SELECT
Closed
, COUNT(Closed) AS 'ClosedNo'
,Open
, COUNT(Open) AS 'OpenNo'
,Plan
, COUNT(Plan) AS 'PlanNo'
FROM
Orders
GROUP BY
Closed, Open, Plan;

Firstly, Open and Date are Keyword(s) in MySQL. You should really name your column to something else; or you will have to use backticks around it.
We can use Coalesce() function to get the Date. It will consider the first non-null value.
Using Count() aggregation function, we can count the non-null rows, for a Date group.
Try the following instead:
SELECT
COALESCE(Closed, `Open`, Plan) AS `Date`,
COUNT(Closed) AS ClosedNo,
COUNT(`Open`) AS OpenNo,
COUNT(Plan) AS PlanNo
FROM Orders
GROUP BY `Date`
RESULT
| Date | ClosedNo | OpenNo | PlanNo |
| ---------- | -------- | ------ | ------ |
| 2018-10-22 | 3 | 0 | 3 |
| 2018-10-23 | 1 | 0 | 1 |
| 2018-10-24 | 0 | 0 | 1 |
| 2018-10-25 | 1 | 1 | 1 |
| 2018-10-26 | 0 | 1 | 0 |
| 2018-10-27 | 0 | 2 | 0 |
View on DB Fiddle

Related

Count null from joined table in MySQL

I need a count of NULL from 2 tables that are joined in MySQL. Sample data like this:
datefield FROM TABLE calendar (contain dates from start to end of this year)
-----------
TABLE value (data stored)
+------------+-------+
| date | keter |
+------------+-------+
| 2021-08-01 | 11 |
| 2021-08-04 | 0 |
| 2021-08-07 | 20 |
| 2021-08-08 | 15 |
| 2021-08-11 | 0 |
+------------+-------+
I am using the following query to combine and display data from calendar and value tables.
SELECT datefield,keter FROM calendar
LEFT JOIN kehadiran ON datefield=tgl AND id_kar IN ('110101')
WHERE datefield BETWEEN '2021-08-01' AND '2021-08-15' GROUP BY datefield;
result :
+------------+-------+
| datefield | keter |
+------------+-------+
| 2021-08-01 | 11 |
| 2021-08-02 | NULL |
| 2021-08-03 | NULL |
| 2021-08-04 | 0 |
| 2021-08-05 | NULL |
| 2021-08-06 | NULL |
| 2021-08-07 | 20 |
| 2021-08-08 | 15 |
| 2021-08-09 | NULL |
| 2021-08-10 | NULL |
| 2021-08-11 | 0 |
| 2021-08-12 | NULL |
| 2021-08-13 | NULL |
| 2021-08-14 | NULL |
| 2021-08-15 | NULL |
+------------+-------+
I use query based on this question (3 table join counting nulls), I didn't get the result I wanted. The query is this :
SELECT SUM(k.keter) FROM kehadiran k
LEFT OUTER JOIN calendar c ON c.datefield = k.keter AND id_kar IN ('110101')
WHERE datefield BETWEEN '2021-08-01' AND '2021-08-12' AND k.keter is NULL;
result:
+--------------+
| SUM(k.keter) |
+--------------+
| NULL |
+--------------+
the result i wanted :
+--------------+
| SUM(k.keter) |
+--------------+
| 10 |
+--------------+
How should I count NULL from the joined table as mentioned above?
You swapped the tables in your last query which is incorrect. Use the query that worked and use COUNT(*) with WHERE right_table.any_notnull_column IS NULL:
SELECT COUNT(*)
FROM calendar
LEFT JOIN kehadiran k ON datefield=tgl AND id_kar IN ('110101')
WHERE datefield BETWEEN '2021-08-01' AND '2021-08-15'
AND k.keter is NULL
You sum up NULL in your query. And a Sum of NULL is NULL. You should just replace SUM(k.keter) with COUNT(k.keter)
See for a small example
To count NULLs, you can use:
SUM(k.keter IS NULL)
Or:
COUNT(*) - COUNT(k.keter)

Output results aggregating column values horizontally

I have this query:
SELECT
count(*), `merchant_id`, `merchant_finance_id`, `merchant_channel_id`, `status`
FROM `application`
WHERE `created_at` >= '2018-04-30' AND `created_at` < '2018-05-01'
GROUP BY `merchant_id`, `merchant_finance_id`, `merchant_channel_id`, `status`
Which results in the following:
-------------------------------------------------------------------------------
| count(*) | merchant_id | merchant_finance_id | merchant_channel_id | status |
-------------------------------------------------------------------------------
| 2 | D8E2459CD78C | 55E4D520AC1C | 66A1861918C5 | ACCEPTED |
| 2 | D8E2459CD78C | 55E4D520AC1C | 66A1861918C5 | REFERRED |
| 1 | E50E50212627 | 6F8F15729DA7 | E02ACD64B452 | AWAITING-ACTIVATION |
| 2 | E50E50212627 | 6F8F15729DA7 | E02ACD64B452 | DEPOSIT-PAID |
| 1 | E50E50212627 | 6F8F15729DA7 | E02ACD64B452 | READY |
| 1 | E50E50212627 | 6F8F15729DA7 | E02ACD64B452 | REFERRED |
| 1 | F04FBD7AEB30 | C11CBD2FC1F8 | 21F2D435EA9D | AWAITING-ACTIVATION |
-------------------------------------------------------------------------------
But is there a way I can arranged the status into sub-columns instead? Eg:
-------------------------------------------------------------------------------
| count(*) | merchant_id | merchant_finance_id | merchant_channel_id | accepted | referred | awaiting_activation | deposit_paid | ready
-------------------------------------------------------------------------------
| 2 | D8E2459CD78C | 55E4D520AC1C | 66A1861918C5 | 2 | 2 | 0 | 0 | 0 |
| 5 | E50E50212627 | 6F8F15729DA7 | E02ACD64B452 | 0 | 1 | 1 | 2 | 1 |
| 1 | F04FBD7AEB30 | C11CBD2FC1F8 | 21F2D435EA9D | 0 | 0 | 1 | 0 | 0 |
-------------------------------------------------------------------------------
Note:
There is a defined list of different status types - so I don't have to worry about "BLAHBLAH" somehow being a status type.
You can try to use condition aggregate function, If you use Mysql you can do simplest like this.
SELECT
count(*),
`merchant_id`,
`merchant_finance_id`,
`merchant_channel_id`,
SUM(`status`='ACCEPTED'),
SUM(`status`='REFERRED'),
SUM(`status`='awaiting_activation'),
SUM(`status`='deposit_paid'),
SUM(`status`='READY')
FROM `application`
WHERE `created_at` >= '2018-04-30' AND `created_at` < '2018-05-01'
GROUP BY `merchant_id`, `merchant_finance_id`, `merchant_channel_id`
TestDLL
CREATE TABLE T(
merchant_id varchar(50),
merchant_finance_id varchar(50),
merchant_channel_id varchar(50),
`status` varchar(50)
);
INSERT INTO T VALUES ('D8E2459CD78C', '55E4D520AC1C','66A1861918C5' ,'ACCEPTED');
INSERT INTO T VALUES ('D8E2459CD78C', '55E4D520AC1C','66A1861918C5' ,'REFERRED');
INSERT INTO T VALUES ('E50E50212627', '6F8F15729DA7','E02ACD64B452' ,'AWAITING-ACTIVATION');
INSERT INTO T VALUES ('E50E50212627', '6F8F15729DA7','E02ACD64B452' ,'DEPOSIT-PAID');
INSERT INTO T VALUES ('E50E50212627', '6F8F15729DA7','E02ACD64B452' ,'READY');
INSERT INTO T VALUES ('E50E50212627', '6F8F15729DA7','E02ACD64B452' ,'REFERRED');
INSERT INTO T VALUES ('F04FBD7AEB30', 'C11CBD2FC1F8','21F2D435EA9D' ,'AWAITING-ACTIVATION');
Query 1:
SELECT
`merchant_id`,
`merchant_finance_id`,
`merchant_channel_id`,
SUM(`status`='accepted') accepted,
SUM(`status`='referred') referred,
SUM(`status`='awaiting_activation') awaiting_activation,
SUM(`status`='deposit_paid') deposit_paid,
SUM(`status`='ready') ready
FROM T
GROUP BY `merchant_id`, `merchant_finance_id`, `merchant_channel_id`
Results:
| merchant_id | merchant_finance_id | merchant_channel_id | accepted | referred | awaiting_activation | deposit_paid | ready |
|--------------|---------------------|---------------------|----------|----------|---------------------|--------------|-------|
| D8E2459CD78C | 55E4D520AC1C | 66A1861918C5 | 1 | 1 | 0 | 0 | 0 |
| E50E50212627 | 6F8F15729DA7 | E02ACD64B452 | 0 | 1 | 0 | 0 | 1 |
| F04FBD7AEB30 | C11CBD2FC1F8 | 21F2D435EA9D | 0 | 0 | 0 | 0 | 0 |

Why data does not match when JOIN same table? [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 5 years ago.
Improve this question
I'm trying to display the table like this
Desired Result:
With the conditions:
tgl1, kondisi_1, kondisi_2, kondisi_3, kondisi_4 is latest condition group by kd_item
tgl2, kond1, kond2, kond3, kond4 is latest data where date <= CURDATE()-INTERVAL 7 DAY group by kd_item
SQL:
http://sqlfiddle.com/#!9/661f7/2
I try to write the query like this,
Query:
SELECT a.kd_item, MAX(a.tanggal) as tgl1, a.kondisi_1, a.kondisi_2, a.kondisi_3, a.kondisi_4,
-- I know min is not the right query
MIN(b.tanggal) as tgl2, b.kondisi_1 as kond1, b.kondisi_2 as kond2, b.kondisi_3 as kond3, b.kondisi_4 as kond4
FROM status_item as a
LEFT JOIN status_item as b ON a.kd_item = b.kd_item
GROUP BY a.kd_item LIMIT 10
When I am joining same table, with the above query, why is the displayed data not related with the date?
How to display date with condition latest date where date less then or equal with 7 days ago?
How to display point 2 at left side of the table?
you should select the max date, join with the data for get column non involved in group by and then join the two different query toghter
select * from (
select a.kd_item, a.tanggal as tgl1, a.kondisi_1, a.kondisi_2, a.kondisi_3, a.kondisi_4
from status_item a
inner join (
SELECT kd_item, MAX(tanggal) as max_tanggal
FROM status_item
group by kd_item
) t1 on t1.max_tanggal = a.tanggal and t1.kd_item = a.kd_item
) t3
inner join (
select b.kd_item, b.tanggal as b_tgl1, b.kondisi_1 as b_kondisi_1, b.kondisi_2 as b_kondisi_2 , b.kondisi_3 as b_kondisi_3, b.kondisi_4 as b_kondisi_4
from status_item b
inner join (
SELECT kd_item, MAX(tanggal) as max_tanggal
FROM status_item
where tanggal <= date_sub(CURDATE(), INTERVAL 7 DAY )
group by kd_item
) t2 on t2.max_tanggal = b.tanggal and t2.kd_item = b.kd_item
) t4 on t3.kd_item= t4.kd_item
Is this what you are looking for?
select
a.kd_item,
a.tanggal as tgl1,
a.kondisi_1,
a.kondisi_2,
a.kondisi_3,
a.kondisi_4,
b.tanggal as tgl2,
b.kondisi_1 as kond1,
b.kondisi_2 as kond2,
b.kondisi_3 as kond3,
b.kondisi_4 as kond4
from
status_item as a
left join
status_item as b
on
a.kd_item = b.kd_item and
b.tanggal <= date_sub(a.tanggal, interval 7 day);
The results are:
+---------+------------+-----------+-----------+-----------+-----------+------------+-------+-------+-------+-------+
| kd_item | tgl1 | kondisi_1 | kondisi_2 | kondisi_3 | kondisi_4 | tgl2 | kond1 | kond2 | kond3 | kond4 |
+---------+------------+-----------+-----------+-----------+-----------+------------+-------+-------+-------+-------+
| 1 | 2017-10-22 | 4 | 0 | 0 | 0 | 2017-10-07 | 3 | 0 | 1 | 0 |
| 1 | 2017-10-17 | 3 | 1 | 0 | 0 | 2017-10-07 | 3 | 0 | 1 | 0 |
| 2 | 2017-12-22 | 3 | 0 | 1 | 0 | 2017-12-12 | 2 | 1 | 0 | 1 |
| 2 | 2017-12-22 | 3 | 0 | 1 | 0 | 2017-10-22 | 4 | 0 | 0 | 0 |
| 2 | 2017-12-12 | 2 | 1 | 0 | 1 | 2017-10-22 | 4 | 0 | 0 | 0 |
| 3 | 2017-12-12 | 4 | 0 | 0 | 0 | 2017-10-22 | 1 | 1 | 1 | 1 |
| 8 | 2017-12-06 | 4 | 0 | 0 | 0 | 2017-11-28 | 0 | 0 | 4 | 0 |
| 1 | 2017-10-07 | 3 | 0 | 1 | 0 | null | null | null | null | null |
| 2 | 2017-10-22 | 4 | 0 | 0 | 0 | null | null | null | null | null |
| 3 | 2017-10-22 | 1 | 1 | 1 | 1 | null | null | null | null | null |
| 4 | 2017-10-22 | 4 | 0 | 0 | 0 | null | null | null | null | null |
| 5 | 2017-10-27 | 4 | 0 | 0 | 0 | null | null | null | null | null |
| 5 | 2017-10-22 | 3 | 0 | 1 | 0 | null | null | null | null | null |
| 6 | 2017-10-22 | 4 | 0 | 0 | 0 | null | null | null | null | null |
| 7 | 2017-10-22 | 4 | 0 | 0 | 0 | null | null | null | null | null |
| 8 | 2017-11-28 | 0 | 0 | 4 | 0 | null | null | null | null | null |
+---------+------------+-----------+-----------+-----------+-----------+------------+-------+-------+-------+-------+
16 rows in set (0.00 sec)
For point 3 in your question, you could add
date_sub(a.tanggal, interval 7 day)
as the first result column:
select
date_sub(a.tanggal, interval 7 day) as week_ago,
a.kd_item,
a.tanggal as tgl1,
...

SQL reduce number of columns in inner query

I have a query:
select
count(*), paymentOptionId
from
payments
where
id in (select min(reportDate), id
from payments
where userId in (select distinct userId
from payments
where paymentOptionId in (46,47,48,49,50,51,52,53,54,55,56))
group by userId)
group by
paymentOptionId;
The problem place is "select min(reportDate), id", this query must return 1 column result, but I can't realize how to do it while I need to group min.
The data set looks like
+----+--------+--------+-----------+---------------------+--------+----------+-----------------+
| id | userId | amount | userLevel | reportDate | buffId | bankQuot | paymentOptionId |
+----+--------+--------+-----------+---------------------+--------+----------+-----------------+
| 9 | 12012 | 5 | 5 | 2014-02-10 23:07:57 | NULL | NULL | 2 |
| 10 | 12191 | 5 | 6 | 2014-02-10 23:52:12 | NULL | NULL | 2 |
| 11 | 12295 | 5 | 6 | 2014-02-11 00:12:04 | NULL | NULL | 2 |
| 12 | 12295 | 5 | 6 | 2014-02-11 00:12:42 | NULL | NULL | 2 |
| 13 | 12256 | 5 | 6 | 2014-02-11 00:26:25 | NULL | NULL | 2 |
| 14 | 12256 | 5 | 6 | 2014-02-11 00:26:35 | NULL | NULL | 2 |
| 16 | 12510 | 5 | 5 | 2014-02-11 00:42:58 | NULL | NULL | 2 |
| 17 | 12510 | 5 | 5 | 2014-02-11 00:43:08 | NULL | NULL | 2 |
| 18 | 12510 | 18 | 5 | 2014-02-11 00:45:16 | NULL | NULL | 3 |
| 19 | 12510 | 5 | 6 | 2014-02-11 01:00:10 | NULL | NULL | 2 |
+----+--------+--------+-----------+---------------------+--------+----------+-----------------+
select count(*), paymentOptionId
from
(select userId, min(reportdate), paymentOptionId
from payments as t1
group by userId, paymentOptionId) as t2
group by paymentOptionId
Fiddle
It first gets the minimum report date (so the first entry) for every user, for every type (so there are two records for a user who has 2 types) and then counts them grouping by type (aka paymentOptionId).
By the way, you can of course cut the attributes chosen in select in from clause, they are only there so you can copy-paste it and see the results it is giving step by step.
You seem to want to report on various payment options and their counts for the earliest ReportDate for each user.
If so, here is an alternative approach
select p.paymentOptionId, count(*)
from payments p
where paymentOptionId in (46,47,48,49,50,51,52,53,54,55,56) and
not exists (select 1
from payments p2
where p2.userId = p.userId and
p2.ReportDate < p.ReportDate
)
group by paymentOptionId;
This isn't exactly the same as your query, because this will only report on the list of payment types, whereas you might want the first payment type for anyone who has ever had one of these types. I'm not sure which you want, though.

How to update MySQL table with a cumulative count of events with the same date

I have a table which I pull data from. This data has a date and a stock symbol. There can be multiple rows of data with the same date and different stock symbols. I need to update the table so that there is a running total for all rows with the same date. When a new date occurs the cumulative count re-sets to 1 and then resumes.
A typical query:
mysql> SELECT Sym 'sym' , fdate as 'FilledDate', TsTradeNum 'numT'
-> FROM trades_entered_b2
-> WHERE fDate >= '2009-08-03' AND fDate <= '2009-08-07'
-> LIMIT 10;
+------+------------+------+
| sym | FilledDate | numT |
+------+------------+------+
| WAT | 2009-08-03 | 0 |
| ALGN | 2009-08-04 | 0 |
| POT | 2009-08-05 | 0 |
| PTR | 2009-08-06 | 0 |
| SCHW | 2009-08-06 | 0 |
| FDO | 2009-08-07 | 0 |
| NBL | 2009-08-07 | 0 |
| RRC | 2009-08-07 | 0 |
| WAT | 2009-08-08 | 0 |
| COCO | 2009-08-08 | 0 |
+------+------------+------+
What I want:
+------+------------+------+
| sym | FilledDate | numT |
+------+------------+------+
| WAT | 2009-08-03 | 1 |
| ALGN | 2009-08-04 | 1 |
| POT | 2009-08-05 | 1 |
| PTR | 2009-08-06 | 1 |
| SCHW | 2009-08-06 | 2 |
| FDO | 2009-08-07 | 3 |
| NBL | 2009-08-07 | 4 |
| RRC | 2009-08-07 | 5 |
| WAT | 2009-08-08 | 1 |
| COCO | 2009-08-08 | 2 |
+------+------------+------+
What I need to do is update the TsTradeNum column with the correct values. I have tried to create a function and various queries all failed.
Any ideas? Thanks in advance
Could try below.The query will increment numT by 1 if the previous row date is same with current row, else it will reset numT to 1.
SELECT sym, FilledDate, numT
FROM(
SELECT sym, FilledDate,
#count:=CASE WHEN ( #date <> FilledDate) THEN 1
ELSE
#count+1
END AS numT,
#date:=FilledDate as dlset
FROM
(SELECT #count:= -1) s,
(SELECT #date:= -1) d,
(SELECT id, sym, FilledDate
FROM mytable3
ORDER BY FilledDate,sym desc
) t ) a