Select NULL otherwise latest date per group - mysql

I am trying to pickup Account with End Date NULL first then latest date if there are more accounts with the same item
Table Sample
Result expected
Select distinct *
from Sample
where End Date is null
Need help to display the output.

Select *
from Sample
order by End_Date is not null, End_date desc

According to sample it seems to me you need union and not exists corelate subquery
select * from table_name t where t.enddate is null
union
select * from table_name t
where t.endate=( select max(enddate) from table_name t1 where t1.Item=t.Item and t1.Account=t.Account)
and not exists ( select 1 from table_name t2 where enddate is null and
t1 where t2.item=t.item
)

SELECT * FROM YourTable ORDER BY End_Date IS NOT NULL, End_Date DESC

In a Derived Table, you can determine the end_date_to_consider for every Item (using GROUP BY Item). IF() the MIN() date is NULL, then we consider NULL, else we consider the MAX() date.
Now, we can join this back to the main table on Item and the end_date to get the required rows.
Try:
SELECT t.*
FROM
Sample AS t
JOIN
(
SELECT
Item,
IF(MIN(end_date) IS NULL,
NULL,
MAX(end_date)) AS end_date_to_consider
FROM Sample
GROUP BY Item
) AS dt
ON dt.Item = t.Item AND
(dt.end_date_to_consider = t.end_date OR
(dt.end_date_to_consider IS NULL AND
t.end_date IS NULL)
)

First of all you should state clearly which result rows you want: You want one result row per Item and TOU. For each Item/TOU pair you want the row with highest date, with null having precedence (i.e. being considered the highest possible date).
Is this correct? Does that work with your real accounts? In your example it is always that all rows for one account have a higher date than all other account rows. If that is not the case with your real accounts, you need something more sophisticated than the following solution.
The highest date you can store in MySQL is 9999-12-31. Use this to treat the null dates as desired. Then it's just two steps:
Get the highest date per item and tou.
Get the row for these item, tou and date.
The query:
select * from
sample
where (item, tou, coalesce(enddate, date '9999-12-31') in
(
select item, tou, max(coalesce(enddate, date '9999-12-31'))
from sample
group by item, tou
)
order by item, tou;
(If it is possible for your enddate to have the value 9999-12-31 and you want null have precedence over this, then you must consider this in the query, i.e. you can no longer simply use this date in case of null, and the query will get more complicated.)

Related

How to conditionally aggregate a value in a select statement?

I need to conditionally be able to get the minimum date value in a sub-select, however I am unable to do this because the query expects me to include the value in my group by statement.
I have a select statement which selects from a sub-select:
SELECT DISTINCT
Begin_Date
FROM
(
SELECT DISTINCT
CASE WHEN (id IS NOT NULL) THEN MIN (start_date)
ELSE initial_date
END AS Begin_Date
FROM ...
)
GROUP BY
Begin_Date
The above query will not allow me to group by the begin_date because of the MIN aggregation I have in the sub-select, however I still need a way to get the minimum start date if the id is not null, or the non aggregated initial_date if the id is null.
Is there any way around this?
in the sub-select, however I still need a way to get the minimum start_date if the id is not null, or the non aggregated initial_date if the id is null.
It looks like a window min would do what you want. Assuming MySQL 8.0:
select begin_date, ...
from (
select case
when id is null then initial_date
else min(start_date) over()
end as begin_date
from ...
) t
group by begin_date
The subquery does not aggregate, but computes the new begin_date based on the rules you described; then you can group by in the outer query.
Side note: on null ids, this gives you the earliest start_date over the whole table; you can add partition by in the over() clause to restrict the range of rows to search.

How do I add a 3rd column to the below to show the most recent date before the max date? So the final output is a 3 column table grouped by user_id?

This is the snipped that shows the latest purchase date.
max(purchase_date) - 1 is what I need, both of them being displayed side by side.
select order.user_id, order.purchase_date
from orders
join
(select id, max(purchase_date) as max_date
from orders
group by id) o2
on orders.user_id = o2.user_id and
orders.purchase_date = o2.max_date
--I believe the follow code should work both PostgreSQL and MySQL.
with a as(
select order.user_id,
order.purchase_date,
max(purchase_date) over(partition by user_id)
from orders order by purchase_date desc
)
select a.*,
lag(purchase_date,1)
over (order by purchase_date desc) as previously_order_date from a;
lag ( value anycompatible [, offset integer [, default anycompatible
]] ) → anycompatible
Returns value evaluated at the row that is offset rows before the
current row within the partition; if there is no such row, instead
returns default (which must be of a type compatible with value). Both
offset and default are evaluated with respect to the current row. If
omitted, offset defaults to 1 and default to NULL.
https://www.postgresql.org/docs/14/functions-window.html
PostgreSQL: https://www.postgresql.org/docs/current/tutorial-window.html
MySQL: https://dev.mysql.com/doc/refman/8.0/en/window-functions-usage.html

Filtering values according to a different value for each user

I am trying to understand how to do in mySQL what I usually do in python.
I have a sales table, with sale_date, user_id and price_USD as columns. Each row is an order made by the user.
I want to get a new table that has all of the orders which cost more than the last order the user made (so in this picture, just the yellow rows).
I know how to get a table with the last order for each user, but I cannot save it on the database.
How do I compare each row's price to a different value by the user_id and get just the larger ones in one 'swoop'?
Thanks
If you are running MysL 8.0, you can do this with window functions:
select t.*
from (
select
t.*,
first_value(price_usd)
over(partition by user_id order by sale_date desc) last_price_usd
from mytable t
) t
where lag_price_usd is null or price > last_price_usd
In earlier versions, you could use a correlated subquery:
select t.*
from mytable t
where t.price_usd > (
select price_usd
from mytable t1
where t1.user_id = t.user_id
order by sale_date desc
limit 1
)

Get column from 2 tables and sort by date

I have 2 tables both containing an event and date column. Is there a way to combine the results of both column's event field into one and sort them by their date field. That way only a single (and combined) event is returned instead of 2.
SELECT event,date FROM table1
UNION
SELECT event,date FROM table2 ORDER BY date
When using UNION you use ORDER by at bottom query it will order marged query
You can't use it except bottom query anyway it should throw an error
SELECT a.event, MAX(a.date) date
FROM
(
SELECT event, date FROM TableA
UNION
SELECT event, date FROM TableB
) a
GROUP BY a.event
ORDER BY a.date DESC

MYSQL: Counting a casted column

I have an table called TableA which has a column called date_entered which is of datetime type. I need to count the number of TableA rows that have been added on a given date.
To accomplish this I must CAST the datetime to a date and COUNT the number of rows that match the given date but i'm unsure how to write this query.
Any help would be much appreciated.
Thanks in advance
Use
select count(*)
from tableA
where date(date_entered) = '2012-11-15'
to count all rows for that date even if the records contain NULL values.
Or use count(specific_column) to count rows that don't contain NULL values for that column.
You can do this:
SELECT COUNT(*), DATE(date_entered) AS date_entered
FROM TableA
GROUP BY date_entered
And change it to:
SELECT COUNT(*), DATE(date_entered) AS date_entered
FROM TableA
WHERE date(date_entered) = <whatever you want>
GROUP BY date_entered
For a specific day.
try something like
SELECT count(*) FROM tableName GROUP BY datefield
OR
SELECT COUNT(*) AS same_date
FROM TableName
GROUP BY datefield
HAVING count(*) >1 ;