MySQL query to order records ORDER BY - php

This question is related to my previous question - MySQL query to show records with current date on top and others as per descending order . The query i uses now is,
SELECT b.sales_id,b.category_id,b.sale_starts,b.sale_ends
FROM tbl_sales b WHERE b.active=1
UNION
SELECT b.sales_id,b.category_id,b.sale_starts,b.sale_ends
FROM tbl_sales b INNER JOIN tb_category c ON b.category_id=c.cat_id
WHERE c.cat_keyword LIKE 'a'
ORDER BY IF(sale_ends = DATE(NOW()), 0, 1), sale_ends DESC
and the results returned is as follows,
sales_id | category_id |sale_starts | sale_ends
----------|---------------------|------------|--------------
4 | 12 | 2012-04-05 | 2012-04-11 (today's date)
1 | 10 | 2012-03-31 | 2012-04-30
2 | 11 | 2012-03-22 | 2012-04-27
3 | 25 | 2012-03-31 | 2012-04-25
5 | 18 | 2012-04-05 | 2012-04-09
6 | 20 | 2012-02-23 | 2012-02-27
7 | 14 | 2012-02-25 | 2012-02-26
But now i am stuck with another issue and i need the to sort the records like shown below -
sales_id | category_id |sale_starts | sale_ends
----------|---------------------|------------|--------------
4 | 12 | 2012-04-05 | 2012-04-11 (today's date)
3 | 25 | 2012-03-31 | 2012-04-25
2 | 11 | 2012-03-22 | 2012-04-27
1 | 10 | 2012-03-31 | 2012-04-30
7 | 14 | 2012-02-25 | 2012-02-26 (expired/past dates)
6 | 20 | 2012-02-23 | 2012-02-27
5 | 18 | 2012-04-05 | 2012-04-09
I had tried using ASC instead of DESC in the query but then the expired dates are listed just after the today's date. I need the future dates to listed after the today's date and after that only the expired dates. How can this be implemented?
Need help. Thanks in advance

ORDER BY will process each condition in order from left to right. So if the ordering you need is something like "Any entries with today's date, then any entries in the future in ascending order of date, then other entries in ascending order of date" you can do something like this
ORDER BY (sale_ends=CURDATE()) DESC,(sale_ends>CURDATE()) DESC,sale_ends ASC
The reason the first two are listed as DESC is that the conditions will evaluate to one if true and zero if false. Since you want the true conditions first then you need to order them in DESCending order.

I might be misunderstanding something, but isn't this what you're looking for?
order by sale_ends < curdate(), sale_ends
Fiddle here.

Related

SQL count and group only returns first row for each group

My table:
+----------+---------------------+
| bonus_id | created |
+----------+---------------------+
| 11 | 2020-04-28 19:50:13 |
| 12 | 2020-04-29 00:00:00 |
| 13 | 2020-04-30 19:55:58 |
| 14 | 2020-04-29 19:56:07 |
| 15 | 2020-04-30 19:56:18 |
| 16 | 2020-04-29 20:16:21 |
+----------+---------------------+
This is what I'm trying to get
2020-04-30 - Count: 2
13
15
2020-04-29 - Count: 3
12
14
16
2020-04-28 - Count: 1
11
This is what I'm getting:
2020-04-30 - Count: 2
13
2020-04-29 - Count: 3
12
2020-04-28 - Count: 1
11
My code:
SELECT DATE(created) as created, COUNT(*) as count, bonus_id FROM test WHERE account_id=? AND user_id=? GROUP BY DATE(created) DESC
I'm getting the correct order with all the outpounts when i use ORDER BY and not GROUP/COUNT, but then I'm not getting the count. Don't understand why I'm only getting the first row for each date.
If you want to add a column with the count to each row, use window functions:
select t.*, count(*) over (partition by date(created)) as day_cnt
from test t;
If you want an aggregated list, then I'll assume you are using MySQL (an old version) or SQLite because these do not generate a syntax error. In that case, you can use group_concat():
select date(created), count(*), group_concat(bonus_id) as bonus_ids
from test
group by date(created);

Confusing about group and having clause with php

I need to get all IDs from table A where all the Expiry date from Table B (INNER JOIN ID = A_ID) are < today (2018-06-29) but i'm not sure and a bit confusing for the query.
Based on my example (2018-06-29) i need to retrieve only Name-4 because ALL Expiry date from Table B are < 2018-06-29
Table A
ID | Name |
-------------
1 | Name-1
2 | Name-2
3 | Name-3
4 | Name-4
5 | Name-5
6 | Name-6
7 | Name-7
Table B
ID | A_ID | Expiry
-----------------------
1 | 1 | 2018-06-29
2 | 2 | 2018-07-29
3 | 2 | 2018-06-29
4 | 3 | 2018-07-29
5 | 3 | 2018-04-29
6 | 4 | 2018-05-29
7 | 4 | 2018-04-29
8 | 6 | 2018-09-29
9 | 6 | 2018-10-29
You are correct that you need both the GROUP BY and the HAVING clauses. Since you require that all expiry dates for a matching A_ID are less than a given date, you must check the MAX() expiry for that grouping.
SELECT ta.* FROM tableA ta JOIN tableB tb ON ta.ID = tb.A_ID
GROUP BY ta.id
HAVING MAX(Expiry) < '2018-06-20';
DEMO

get 12 month application count form SQL and start count form previous 3 month

This my Table Structure
###Table ###Expected Outpoot
ID | create_date Month | Application | Year
------------------------------ --------------------------
1 | 2017-06-25 10:00:11 10 | 0 | 2016
2 | 2017-06-26 10:00:11 11 | 0 | 2016
3 | 2017-07-02 10:00:11 12 | 0 | 2016
4 | 2017-07-25 10:00:11 1 | 0 | 2017
5 | 2017-08-21 10:00:11 2 | 0 | 2017
6 | 2017-08-22 10:00:11 3 | 0 | 2017
7 | 2017-08-25 10:00:11 4 | 0 | 2017
5 | 0 | 2017
6 | 2 | 2017
7 | 2 | 2017
8 | 3 | 2017
9 | 0 | 2017
I am Trying to get the monthly data count from my table. I want to start the count form Previous 3 month.
This is what I have tried so far?
Edit: I am close to solve the issue.Here is the query and result.
select date_format(tn.create_date,'%Y-%m') as mon,
count(*) as num
FROM table_name as tn
GROUP BY mon order by mon;
Month | Application
--------------------------------
2017-06 | 2
2017-07 | 2
2017-08 | 3
So, How do i get my expected output?
Here is the Query Fiddle
You need a list of months to join into your query. You can make a table for it, as #JohnHC suggested or use this hack to list the months like this:
set #start='2017-06-01';
select YEAR(date), MONTH(date), COUNT(create_date) from
(
select adddate(#start, INTERVAL #num:=#num+1 MONTH) date
from test, (select #num:=-9) num
limit 12
) as dt
LEFT JOIN test ON MONTH(create_date) = MONTH (date) and YEAR(create_date) = YEAR(date)
GROUP BY date;
Notice, that in the dt query, the actual data from the test table is not accessed, but it is required to contain at least 12 rows to work. Also, you don't need to use the same table for generating the month sequence what you use for querying the create_date.
You can set the start of the interval in the #num:=-9 expression. -9 in this case means 9 months before #start date. You can set the length of the interval in the LIMIT clause.
Example fiddle.

MySQL query to show records with current date on top and others as per descending order

I am using the following query in my database,
SELECT b.sales_id,b.category_id,b.sale_starts,b.sale_ends
FROM tbl_sales b WHERE b.active=1
UNION
SELECT b.sales_id,b.category_id,b.sale_starts,b.sale_ends
FROM tbl_sales b INNER JOIN tb_category c ON b.category_id=c.cat_id
WHERE c.cat_keyword LIKE 'a' ORDER BY sale_ends DESC
and getting the result as follows,
sales_id | category_id |sale_starts | sale_ends
----------|---------------------|------------|--------------
1 | 10 | 2012-03-31 | 2012-04-30
2 | 11 | 2012-03-22 | 2012-04-27
3 | 25 | 2012-03-31 | 2012-04-25
4 | 12 | 2012-04-05 | 2012-04-11
Now i need to get the result as follows, ie the row which has today's date/current date assale_ends must be shown in the top of the order (assuming today's date/current date is 2012-04-11), like shown below-
sales_id | category_id |sale_starts | sale_ends
----------|---------------------|------------|--------------
4 | 12 | 2012-04-05 | 2012-04-11 (today's date)
1 | 10 | 2012-03-31 | 2012-04-30
2 | 11 | 2012-03-22 | 2012-04-27
3 | 25 | 2012-03-31 | 2012-04-25
Need help in this, thanks in advance.
Try this ORDER BY clause with condition -
ORDER BY IF(sale_ends = DATE(NOW()), 0, 1), sale_ends DESC
You can wrap the whole thing in another SELECT and use ORDER BY
SELECT * FROM (
SELECT b.sales_id,b.category_id,b.sale_starts,b.sale_ends
FROM tbl_sales b WHERE b.active=1
UNION
SELECT b.sales_id,b.category_id,b.sale_starts,b.sale_ends
FROM tbl_sales b INNER JOIN tb_category c ON b.category_id=c.cat_id
WHERE c.cat_keyword LIKE 'a' ORDER BY sale_ends DESC
) AS all_sales
ORDER BY (sale_ends=CURDATE()) DESC, sale_ends DESC

Query union, if search result is less than 10, fill with others from database order by date

I want to make a mysql union search. My purpose is: my total results back must be 10.
if search results are more than 10, the returned data come all from search result.
if search results are less than 10, first few returned data come from search result, and then fetch the remaining results from database order by date.
To make it clearer: if a client searches "today", my database only returns 7 results which contain "today", then add another 3 results from my database ORDER BY date. So that the total results are 10 items.
Another purpose: another 3 results are not repetitions from the 7 results which match the search. I think UNION or UNION DISTINCT can do that job, am I right?
So, how do I do a query like this?
PS: my code will fix the result order, but I need first select is always behind the second select
(SELECT * FROM table WHERE title like %$searchword% limit 0,10 ORDER BY date)
UNION
(SELECT * FROM table limit 0,10 ORDER BY date)
limit 0,10 ORDER BY date
If you always want 10 results:
SELECT
IF(m.id,1,0) AS has_match,
t.*
FROM
`table` t
LEFT JOIN `table` m ON m.id = t.id AND m.title LIKE '%$searchword%'
GROUP BY t.id
ORDER BY has_match DESC, date
LIMIT 10
Tested:
mysql> select * from `table`;
+----+------------------------+---------------------+
| id | title | date |
+----+------------------------+---------------------+
| 1 | test 1 | 2011-11-06 10:27:08 |
| 2 | test 2 match | 2011-11-06 10:27:14 |
| 3 | 3 match this too | 2011-11-06 10:27:23 |
| 4 | title does NOT | 2011-11-06 10:27:44 |
| 5 | Another matching title | 2011-11-06 10:27:55 |
| 6 | this does not either | 2011-11-06 10:29:22 |
| 7 | Do not put this first | 2011-11-06 10:29:37 |
| 8 | Is this number 8? | 2011-11-06 10:29:57 |
| 9 | The 9th is a match | 2011-11-06 10:30:07 |
| 10 | 10th does not | 2011-11-06 10:30:20 |
| 11 | 11th IS a match too! | 2011-11-06 10:30:37 |
| 12 | 12th gets ignored? | 2011-11-06 10:30:49 |
+----+------------------------+---------------------+
12 rows in set (0.00 sec)
mysql> SELECT IF(m.id,1,0) AS has_match, t.* FROM `table` t LEFT JOIN `table` m ON m.id = t.id AND m.title LIKE '%match%' GROUP BY t.id ORDER BY has_match DESC, date LIMIT 10;
+-----------+----+------------------------+---------------------+
| has_match | id | title | date |
+-----------+----+------------------------+---------------------+
| 1 | 2 | test 2 match | 2011-11-06 10:27:14 |
| 1 | 3 | 3 match this too | 2011-11-06 10:27:23 |
| 1 | 5 | Another matching title | 2011-11-06 10:27:55 |
| 1 | 9 | The 9th is a match | 2011-11-06 10:30:07 |
| 1 | 11 | 11th IS a match too! | 2011-11-06 10:30:37 |
| 0 | 1 | test 1 | 2011-11-06 10:27:08 |
| 0 | 4 | title does NOT | 2011-11-06 10:27:44 |
| 0 | 6 | this does not either | 2011-11-06 10:29:22 |
| 0 | 7 | Do not put this first | 2011-11-06 10:29:37 |
| 0 | 8 | Is this number 8? | 2011-11-06 10:29:57 |
+-----------+----+------------------------+---------------------+
10 rows in set (0.00 sec)

Categories