Is there a possibility to get the closest value lower than a specific value with a group function without a join?
date productId stock
2014-12-27 1 10
2014-12-31 1 20
2015-01-05 1 30
2014-12-28 2 10
2015-01-04 2 20
The value is for example the date and should be lower than 2015-01-01 but the highest date value and the result should be ordered by the stock sac, so the result should be:
date productId stock
2014-12-28 2 10
2014-12-31 1 20
Of course, this could be solves with a join, but a join is slower in large tables, isn't it?
You're looking for the last day of 2014, it seems, for each distinct product id.
You do that with
SELECT MAX(date) date, product_id
FROM yourtable
WHERE date < '2015-01-01'
GROUP BY product_id
That gives you a collection of date, product_id. A compound index on (date, product_id) will make this query very efficient to evaluate.
Then you join that to your main table, like so.
SELECT a.*
FROM yourtable AS a
JOIN (
SELECT MAX(date) date, product_id
FROM yourtable
WHERE date < '2015-01-01'
GROUP BY product_id
) AS b USING(date,product_id)
ORDER BY a.product_id, a.date
and that retrieves the detail records for the last item in 2014. The same compound index will accelerate the JOIN.
You're worried about JOIN performance, and that's legitimate. But it can be improved with proper indexing. There really isn't a better way to do it.
Related
I have this date set table:
Product Entry_Date
1-A 18-02-2020
2-A 19-02-2020
1-A 23-02-2020
3-C 25-02-2020
4-D 26-02-2020
2-A 27-02-2020
I need those products which have Entry_Date between 23rd to 27th Feb BUT do not have entries before.
For eg. the output should be
Product
3-C
4-D
I tried two approaches:
This works:
select Product
from table a join (select Product, min(Entry_date) as min_date from table) b on a.Product = b.Product
where Entry_date between '23-02-2020' and '27-02-2020'
and b.min_date >='23-02-2020'
and this does not:
select Product
from table
where Entry_Date between '23-02-2020' and '27-02-2020'
group by 1
having min(Entry_Date)>='23-02-2020'
Is there any elegant way of doing this. Why does the second method does not work?
Use aggregation and min() in the having clause:
select product
from t
group by product
having min(Entry_Date) between '2020-02-23' and '2020-02-27';
Here is a db<>fiddle.
Note that I also fixed your date constants so they are YYYY-MM-DD standard.
I need to retrieve the last two dates for customers with entries in at least two different dates, implying there are some customer who had purchased only in one date, the table is as follow
client_id date
1 2016-07-02
1 2016-07-02
1 2016-06-01
2 2015-06-01
as a response, I would get
client_id previous_date last_date
1 2016-06-01 2016-07-02
important:
a client can have multiple entries for the same date
a client can have entries only for one date, such customer should be discarded
Try this: group by the client_id column, with a having of count(*) > 1 to find results with more than one result. Then do a check of the min and max date, to ensure they aren't the same. Then just select the date, and order the results by date in desc order, with a limit of 2.
select
date
from
my_table
group by
client_id
having
min(date) <> max(date)
and count(*) > 1
order by
date desc
limit 2
I have this:
SELECT * FROM history JOIN value WHERE history.the_date >= value.the_date
is it possible to somehow to ask this question like, where history.the_date is bigger then or equal to biggest possible value of value.the_date?
HISTORY
the_date amount
2014-02-27 200
2015-02-26 2000
VALUE
the_date interest
2010-02-10 2
2015-01-01 3
I need to pair the correct interest with the amount!
So value.the_date is the date since when the interest is valid. Interest 2 was valid from 2010-02-10 till 2014-12-31, because since 2015-01-01 the new interest 3 applies.
To get the current interest for a date you'd use a subquery where you select all interest records with a valid-from date up to then and only keep the latest:
select
the_date,
amount,
(
select v.interest
from value v
where v.the_date <= h.the_date
order by v.the_date desc
limit 1
) as interest
from history h;
use join condition after ON not in where clause...
SELECT * FROM history JOIN (select max(value.the_date) as d from value) as x on history.the_date >= x.d
WHERE 1=1
Presumably, you want this:
select h.*
from history h
where h.the_date >= (select max(v.the_date) from value v);
I have this table:
-----------------------------------------------------------
| id | name | date | count | balance |
-----------------------------------------------------------
1 a 0000-00-00 1 10
2 b 2014-10-02 1 20
3 c 2014-09-01 1 30
4 d 2014-09-16 1 40
I need to get the SUM of the four count & balance column on my SELECT, then order it by the date in ascending but I need to make sure it should not be the 0000-00-00. I tried this syntax but it does not order the date the way I wanted.
SELECT
date,
SUM(count) AS deposit_counts,
SUM(balance) AS balance_sum
FROM tbl
ORDER BY date ASC
My expected output:
-------------------------------------------
| date | count | balance |
-------------------------------------------
2014-09-01 4 90
Use MIN and NULLIF functions:
SELECT
MIN(NULLIF(date, '0000-00-00')) AS min_date,
SUM(count) AS deposit_counts,
SUM(balance) AS balance_sum
FROM tbl
Test it here: http://sqlfiddle.com/#!2/d43acf/1
I wish I understood the point in having a 0000-00-00 date as opposed to having null so only one possibility needs ruling out... Anyway at first I would assume you might want to get the total balances of each day and would require a query along these lines
SELECT
date,
sum(count) AS deposit_counts,
SUM(balance) AS balance_sum
FROM tbl
WHERE date <> '0000-00-00'
GROUP BY date
ORDER BY date
which would output
2014-09-01 1 30
2014-09-16 1 40
2014-10-02 1 20
but as it stands it appears you don't, I'm not one hundred percent sure what your ultimate goal is in terms of future querying so I will guess you want a historical value of balances up to the current date, ruling out the weird zero date thing. In which case you might want a greater than WHERE clause, and presumably just the lowest value in the date column to show the total from this date like so:
SELECT
min(date) AS date,
sum(count) AS deposit_counts,
SUM(balance) AS balance_sum
FROM tbl
WHERE date > '0000-00-00'
since it would ignore the invalid date it will return
2014-09-01 3 80
I hope this is of some use.
Edit:
if you absolutely require all values then you will want to use a subquery to retrieve and rule out the exceptional date result like so:
SELECT
(SELECT min(date) FROM tbl WHERE date > '0000-00-00') AS date,
sum(count) AS deposit_counts,
SUM(balance) AS balance_sum
FROM tbl
or as above, nullif on your date query should work too
I have a table with prices and dates on product:
id
product
price
date
I create a new record when price change. And I have a table like this:
id product price date
1 1 10 2014-01-01
2 1 20 2014-02-17
3 1 5 2014-03-28
4 2 25 2014-01-05
5 2 12 2014-02-08
6 2 30 2014-03-12
I want to get last price for all products. But when I group with "product", I can't get a price from a row with maximum date.
I can use MAX(), MIN() or COUNT() function in request, but I need a result based on other value.
I want something like this in final:
product price date
1 5 2014-03-28
2 30 2014-03-12
But I don't know how. May be like this:
SELECT product, {price with max date}, {max date}
FROM table
GROUP BY product
Alternatively, you can have subquery to get the latest get for every product and join the result on the table itself to get the other columns.
SELECT a.*
FROM tableName a
INNER JOIN
(
SELECT product, MAX(date) mxdate
FROM tableName
GROUP BY product
) b ON a.product = b.product
AND a.date = b.mxdate
I think the easiest way is a substring_index()/group_concat() trick:
SELECT product,
substring_index(group_concat(price order by date desc), ',', 1) as PriceOnMaxDate
max(date)
FROM table
GROUP BY product;
Another way, that might be more efficient than a group by is:
select p.*
from table t
where not exists (select 1
from table t2
where t2.product = t.product and
t2.date > t.date
);
This says: "Get me all rows from the table where the same product does not have a larger date." That is a fancy way of saying "get me the row with the maximum date for each product."
Note that there is a subtle difference: the second form will return all rows that on the maximum date, if there are duplicates.
Also, for performance an index on table(product, date) is recommended.
You can use a subquery that groups by product and return the maximum date for every product, and join this subquery back to the products table:
SELECT
p.product,
p.price,
p.date
FROM
products p INNER JOIN (
SELECT
product,
MAX(date) AS max_date
FROM
products
GROUP BY
product) m
ON p.product = m.product AND p.date = m.max_date
SELECT
product,
price,
date
FROM
(SELECT
product,
price,
date
FROM table_name ORDER BY date DESC) AS t1
GROUP BY product;