How to get the latest value? - mysql

I am trying to write a query and I want to get only the max(date), and I have to group by the rest of info such as job_ID, invoice, total_paid, and payment_method.
I can't group by the payment method because logically its not correct and also because the payment methods are different... and, I cannot use listagg here.
Any idea how can I accomplish my goal?
I almost reached the end but the payment method cause some errors in the code...
Thank you in advance :)

You can get the row with the max date for any id with a qualify row_number() over():
with data as (
select $1 id, $2 date, $3 value
from values (1, 1, 'a')
, (1, 2, 'b')
, (1, 3, 'c')
, (2, 1, 'e')
, (2, 2, 'f')
, (2, 3, 'g')
)
select *
from data
qualify row_number() over(partition by id order by date desc) = 1
;
If this is not what you want — you will need to improve the question by detailing sample input data and desired results.

Related

MySQL Selecting wrong column value in Group By query with alias in where clause

I know this question was already asked in a similar way, but I could not found any with an alias in the where clause.
I have a table structure like this:
CREATE TABLE Orders
( ID int NOT NULL Primary Key
, OrderNr VARCHAR(6) NOT NULL
, Date DATE NOT NULL
, Time CHAR(6) NOT NULL
, GeoCode CHAR(6) NULL) ;
My insert looks like this:
INSERT INTO orders (ID, OrderNr, Date, Time, GeoCode) VALUES (1, '123456', '2022-02-
15', '111110', '4022')
, (2, '123457', '2022-02-15', '121210', '4022')
, (3, '123455', '2021-04-15', '171515', '4020')
, (4, '123455', '2021-04-16', '150302', '4022')
, (5, '123466', '2022-03-03', '191810', '4020')
, (6, '123466', '2022-03-04', '121410', '4022')
Now I´m trying to get the latest Date and Time values for all OrderNr like this:
SELECT ID, OrderNr, MAX(cast(concat(Date, ' ', cast(Time as Time)) as datetime)) as
DateAndTime, GeoCode
FROM Orders o1
GROUP BY OrderNr
The Results shows the right latest date and time but the GeoCode is wrong. E.g for the
OrderNr 123455 it is 4020 but should be 4022.
I know that similar question were already asked but I cant use the alias in the where clause. Can somebody explain to me what I´m doing wrong?
Thank you very much in advance.
If your mysql version support ROW_NUMBER window function you can try this
SELECT *
FROM (
SELECT ID,
OrderNr,
cast(concat(Date, ' ', cast(Time as Time)) as datetime) DateAndTime,
GeoCode,
ROW_NUMBER() OVER(PARTITION BY OrderNr ORDER BY cast(concat(Date, ' ', cast(Time as Time)) as datetime) DESC) rn
FROM Orders o1
) t1
WHERE rn = 1
or use subquery with EXISTS
SELECT *
FROM Orders o1
WHERE EXISTS (
SELECT 1
FROM Orders oo
WHERE oo.OrderNr = o1.OrderNr
HAVING MAX(oo.Date) = o1.Date
)
sqlfiddle

How to get the average number of Item Sold per week in SQL?

I have table of sold item which has following columns like
SoldItemID
SoldID
SoldAmount
DateOfPurchase
DateOfActivation
CreatedDate
How to get the average number of Item sold Per week in SQL?
Any help would be highly appreciated!
I know I am late to the party, but just in case other people are looking, this might work:
select date_part('week', transaction_date) week_of_the_year, item_id,
avg(sold_qty) from your_table group by 1, 2 order by 1
For SQL SERVER
WITH CTE AS(
SELECT
*
FROM (
VALUES
('2018-08-23', 'A', 10),
('2018-08-23', 'B', 10),
('2018-08-24', 'A', 14),
('2018-08-31', 'A', 8),
('2018-08-31', 'B', 10)
) as list (Date_, Item, Amount)
)
select
WKnum, MIN(Date_), MAX(Date_), Item, AVG(Amount)
from(
select
*,
DATEPART(WK, Date_) WKnum
from CTE
) as A
group by WKnum, Item
Try below query: it will work on sql server
select datepart(week,DateOfPurchase),avg(item)
from
(
select DateOfPurchase,count(SoldItemID) item
from tablename group by DateOfPurchase) a
group by datepart(week,DateOfPurchase)

GROUP CONCAT with ORDER in MEMSQL

Here is a toy example:
CREATE TABLE TEST
(
ID INT,
AGG NVARCHAR(20),
GRP NVARCHAR(20)
);
INSERT INTO TEST VALUES
(1, 'AB', 'X'), (2, 'BC', 'X'), (3, 'AC', 'X'),
(4, 'EF', 'Y'), (5, 'FG', 'Y'), (6, 'DC', 'Y'),
(7, 'JI', 'Z'), (8, 'IJ', 'Z'), (9, 'JK', 'Z');
Now, I would like to do this (this is a valid code in MySQL, but not in MEMSQL):
SELECT
COUNT(*),
SUM(ID),
GROUP_CONCAT(AGG ORDER BY AGG),
GRP
FROM TEST
GROUP BY GRP
So that the output looks like this (Required Output):
3 6 AB,AC,BC X
3 15 DC,EF,FG Y
3 24 IJ,JI,JK Z
Note that the values in the third column are sorted for each row. My output looks like this (Current Wrong Output):
3 6 BC,AB,AC X
3 15 DC,EF,FG Y
3 24 IJ,JI,JK Z
Compare each row in the third column, the lists are sorted.
However, since the above query is not valid in MEMSQL, I have to remove the ORDER BY AGG part in GROUP_CONCAT which causes the third column to not be sorted.
As per the documentation of GROUP_CONCAT, the expression can also be a function, however, there is no built in function to sort. I have tried many combinations of SELECT ... ORDER BY statements in GROUP_CONCAT without success. Is this impossible to do, or am I missing something?
I think this works for my case.
SELECT
COUNT(*),
SUM(T.ID),
GROUP_CONCAT(T.AGG),
T.GRP
FROM (
SELECT
*,
RANK() OVER(PARTITION BY GRP ORDER BY AGG) AS R
FROM TEST
) T
GROUP BY T.GRP
ORDER BY T.R
It is rather convoluted, so I hope someone can suggest an improvement.
Try this:
SELECT
COUNT(*),
SUM(ID),
GROUP_CONCAT(AGG),
GRP
FROM TEST
GROUP BY GRP
ORDER BY GROUP_CONCAT(AGG)

Get n oldest rows, but no more than x that have the same value in a column

I have a simple table
CREATE TABLE `example` (
`id` int(12) NOT NULL,
`food` varchar(250) NOT NULL
);
With the following data
INSERT INTO `example` (`id`, `food`) VALUES
(1, 'apple'),
(2, 'apple'),
(3, 'apple'),
(4, 'apple'),
(5, 'apple'),
(6, 'apple'),
(7, 'apple'),
(8, 'banana'),
(9, 'banana'),
(10, 'potato'),
(11, 'potato'),
(12, 'potato'),
(13, 'banana'),
(14, 'banana'),
(15, 'banana');
I want to get the oldest 10 rows
SELECT *
FROM example
ORDER BY id ASC
LIMIT 10
But I don't want to get more than 5 rows where food has the same value.
My current query receives 7 apple (more than I want), 2 banana, and 1 potato. In the data provided, I'd want to receive 5 apple, 2 banana, and 3 potato.
How can I accomplish this?
Update:
SQL Group BY, Top N Items for each Group is not a duplicate because it involves a different database. In particular, GROUP BY works different in sql-server than it does in MySQL
You can add a count (in reverse) for each food . . . using variables or a correlated subquery. This will use the latter:
select t.*
from (select t.*,
(select count(*) from example t2 where t2.food = t.food and t2.id >= t.id) as seqnum
from example t
) t
where seqnum <= 5
order by id desc
limit 10;
I didn't create the table and test this, but it should give you what you want. Just a different approach than the one above.
Select *
From (Select ID, Food
, Count(Food) Over(Partition By Food Order by ID) as Appearances
From Your_Table) as a
Where a.Appearances <= 5
Order By ID Asc
You can obviously put the limit if you want.

mysql force order of results found to match order of IN clause

This question is different to a commonly asked question about ordering the final results by the IN clause.
I would like to force the results returned by the query that contains the IN clause, to match the order of the IN clause.
This is the original question that I am working from.
I'd like to alter the query below so that a row containing progress=2 occurs before progress=4 and progress=7 for each session_id when ordering the formation_page_hits table by datetime.
Here is the current query:
SELECT COUNT(*)
FROM (
SELECT session_id
FROM formation_page_hits
WHERE progress IN (2, 4, 7)
AND datetime >= '2011-03-23'
AND datetime < '2011-03-24'
GROUP BY
session_id
HAVING COUNT(DISTINCT progress) = 3
) q
These entries
datetime, session_id, progress
('2011-03-01 01:02:11', 'abc', 2)
('2011-03-01 01:02:12', 'abc', 4)
('2011-03-01 01:02:13', 'abc', 7)
should be a match for the query, but:
datetime, session_id, progress
('2011-03-01 01:02:11', 'abc', 4)
('2011-03-01 01:02:12', 'abc', 2)
('2011-03-01 01:02:13', 'abc', 7)
should not be a match.
Additionally:
datetime, session_id, progress
('2011-03-01 01:02:11', 'abc', 4)
('2011-03-01 01:02:12', 'abc', 2)
('2011-03-01 01:02:13', 'abc', 4)
('2011-03-01 01:02:14', 'abc', 7)
should be a match.
The more common way is to double self-join to end up with a three way join ON ascending date time. That, however, is hardly a well performing query.
select *
from
(
SELECT session_id, group_concat(concat('|',progress,'/') order by datetime) list
FROM formation_page_hits
WHERE progress IN (2, 4, 7)
AND datetime >= '2011-03-23'
AND datetime < '2011-03-24'
GROUP BY session_id
HAVING COUNT(DISTINCT progress) = 3
) X
where list like '%|2/%|4/%|7/%'