Selecting Date and ID from a table with max value of Amount - sql

I am trying to fetch the Date and VisitorID from a payment table having the maximum value of amount. I know how to find max value by each date but I am unable to fetch the Date and VisitorID having the maximum value of amount.
I tried to use the attached code below but I just get one value having max value. I am trying to get date and visitor ID from each day with maximum value of amount.
SELECT Date, visitorID
FROM payment
WHERE Amount =
(
SELECT MAX(Amount)
FROM payment
)

You can try using correlated subquery
SELECT Date, visitorID,amount
FROM payment a
WHERE exists
(
SELECT 1
FROM payment b where a.date=b.date group by b.date having max(b.amount)=a.amount
)

One option uses a subquery:
SELECT p1.Date, p1.visitorID
FROM payment p1
INNER JOIN
(
SELECT Date, MAX(Amount) AS max_amount
FROM payment
GROUP BY Date
) p2
ON p1.Date = p2.Date AND p1.Amount = p2.max_amount;
The subquery finds, for each date, the maximum amount. Then, we join this to your original table to effectively filter off any record for a given date which does not have the maximum amount.
If your version of SQL supports analytic functions, then we can use them instead:
SELECT Date, visitorID
FROM
(
SELECT p.*, ROW_NUMBER() OVER (PARTITION BY Date ORDER BY Amount DESC) rn
FROM payment p
) t
WHERE rn = 1;
If you also wanted to have all records for a given date which are tied for the highest amount, then replace ROW_NUMBER above with either RANK or DENSE_RANK.

After seeing your comments it seems you need row_number()
with cte as
(
SELECT *,row_number() over(partition by date order by amount desc)rn
from payment t1
) select * from cte where cte.rn=1

You were close, you need reference from the outerquery to make it correlated subquery :
SELECT p.Date, p.visitorID
FROM payment p
WHERE p.Amount = (SELECT MAX(p1.Amount) FROM payment p1 WHERE p1.Date = p.Date);

Related

SQL Query - second ID of a list ordered by date and ID

I have a SQL database with a list of Customer IDs CustomerID and invoices, the specific product purchased in each invoice ProductID, the Date and the Income of each invoice . I need to write a query that will retrieve for each product, which was the second customer who made a purchase
How do I do that?
EDIT:
I have come up with the following query:
SELECT *,
LEAD(CustomerID) OVER (ORDER BY ProductID, Date) AS 'Second Customer Who Made A Purchase'
FROM a
ORDER BY ProductID, Date ASC
However, this query presents multiple results for products that have more than two purchases. Can you advise?
SELECT a2.ProductID,
(
SELECT a1.CustomerID
FROM a a1
WHERE a1.ProductID = a2.ProductID
ORDER BY Date asc
LIMIT 1,1
) as SecondCustomer
FROM a a2
GROUP BY a2.ProductID
I need to write a query that will retrieve for each product, which was the second customer who made a purchase
This sounds like a window function:
select a.*
from (select a.*,
row_number() over (partition by productid order by date asc) as seqnum
from a
) a
where seqnum = 2;

Second minimum value for every customer

I am using MySQL database. So, there are two columns I am working on, CustomerId, and OrderDate. I want to find a second-order date (2nd minimum order date) for each customer.
If you are using MySQL 8+, then ROW_NUMBER can be used here:
WITH cte AS (
SELECT *, ROW_NUMBER() OVER (PARTITION BY CustomerId ORDER BY OrderDate) rn
FROM yourTable
)
SELECT CustomerId, OrderDate
FROM cte
WHERE rn = 2;
I would recommend using dense_rank as it can give you correct result even if there is duplicate order_date as follows:
SELECT * FROM
(SELECT t.*, DENSE_RANK() OVER (PARTITION BY CustomerId ORDER BY OrderDate) dr
FROM yourTable t
) t where dr = 2;
You can use corelated sub-query as follows if your MySQL version do not support analytical functions as follows:
SELECT T.*
FROM YOURTABLE T
WHERE 1 = (
SELECT COUNT(DISTINCT ORDER_DATE)
FROM YOURTABLE TT
WHERE TT.ORDER_DATE > T.ORDER_DATE
)
I would use a subquery like this:
select o.*
from orders o
where o.order_date = (select o2.order_date
from orders o2
where o2.customer_id = o.customer_id
order by o2.order_date
limit 1 offset 1
);
The subquery is a correlated subquery that returns the second date. If you want the second date with other columns, it can be moved to the select.
With an index on (customer_id, order_date), this is likely to be the fastest solution.
This assumes that there is one row per date (or that if there are multiple rows, "second" can be the earliest date). If you want the second distinct date then use select distinct int he subquery -- however select distinct and group by would incur additional overhead.

SQLite query with LIMIT per column

I am trying to compose a query with a where condition to get multiple unique sorted columns without having to do it in multiple queries. That is confusing so here is an example...
Price Table
id | item_id | date | price
I want to query to find the most recent price of multiple items given a date. I was previously iterating through items in my application code and getting the most recent price like this...
SELECT * FROM prices WHERE item_id = ? AND date(date) < date(?) ORDER BY date(date) DESC LIMIT 1
Iterating through each item and doing a query is too slow so I am wondering if there is a way I can accomplish this same query for multiple items in one go. I have tried UNION but I cannot get it to work with the ORDER BY and LIMIT commands like this thread says (https://stackoverflow.com/a/1415380/4400804) for MySQL
Any ideas on how I can accomplish this?
Try this (based on adapting the answer):
SELECT * FROM prices a WHERE a.RowId IN (
SELECT b.RowId
FROM prices b
WHERE a.item_id = b.item_id AND date < ?
ORDER BY b.item_id LIMIT 1
) ORDER BY date DESC;
Window functions (Available with sqlite 3.25 and newer) will likely help:
WITH ranked AS
(SELECT id, item_id, date, price
, row_number() OVER (PARTITION BY item_id ORDER BY date DESC) AS rn
FROM prices
WHERE date < ?)
SELECT id, item_id, date, price
FROM ranked
WHERE rn = 1
ORDER BY item_id;
will return the most recent of each item_id from all records older than a given date.
I would simply use a correlated subquery in the `where` clause:
SELECT p.*
FROM prices p
WHERE p.DATE = (SELECT MAX(p2.date)
FROM prices p2
WHERE p2.item_id = p.item_id
);
This is phrase so it works on all items. You can, of course, add filtering conditions (in the outer query) for a given set of items.
With NOT EXISTS:
SELECT p.* FROM prices p
WHERE NOT EXISTS (
SELECT 1 FROM prices
WHERE item_id = p.item_id AND date > p.date
)
or with a join of the table to a query that returns the last date for each item_id:
SELECT p.*
FROM prices p INNER JOIN (
SELECT item_id, MAX(date) date
FROM prices
GROUP BY item_id
) t ON t.item_id = p.item_id AND t.date = p.date

How to select the record with minimum value from table?

I have table BIDS, which contains a lot of columns and rows but I only want to select a row which contains lowest BIDPRICE.
Select min(Cast(Bids.BidPrice as INT)), BidBidderName from bids BidBidderName
but it throws error
Column 'bids.BidBidderName' is invalid in the select list because it
is not contained in either an aggregate function
When I put BidderName in Group by then it shows all records but I only want record which contains lowest bid price.
Here is an option that will get just the row with the lowest price.
Select top 1 BidPrice
, BidBidderName
from bids
order by Cast(BidPrice as INT)
You can use subquery:
Select BidPrice, BidBidderName from bids
where Bids.BidPrice in (Select min(Cast(b.BidPrice as INT)) from bids b)
Or INNER JOIN:
Select b1.BidPrice, b1.BidBidderName from bids b1
inner join (select Min(BidPrice) BidPrice from #bids) as b2 on b.BidPrice = b2.BidPrice
If you only want rows that have the lowest bid price one solution is to use a subquery to find the minimum price like this:
Select BidPrice, BidBidderName
from bids
where BidPrice = (select min(Cast(BidPrice as INT)) from bids)
If the BidPrice is either money or a numeric type (which it most likely should be) the cast to int is not necessary.
If you do
Select Min(BidPrice) BidPrice, BidBidderName
from bids
group by BidBibberName
you would instead get the lowest bid for every bidder.
try:
Row_Number()
;with cte1
as
(
select BidderName ,BidPrice,Row_Number() Over(order by price asc) as rn from bids
)
select * from cte1 where rn=1;
Or
Min(BidPrice) Over(PARTITION BY BidderName order by price asc)
select top 1 BidderName ,Min(BidPrice) Over(PARTITION BY BidderName order by price asc) as minBidPrice from bids

sql, return only the max version of a record from a table

I have the following table which has a few key fields. the most important being the version and the dates.
I need a query that will allow me to display the active prices in the system for each of the company and products.
so show all dates between start and end, easy enough
show only the maximum version with those results - this is where I am stuck.
I have created a fiddle to show my example
http://sqlfiddle.com/#!6/e0d4f/3
how can I return only the record for each company and product that has the highest version within the date ranges?
this is what I have so far but incomplete:
select * from
prices
where getdate() between [start] and [end]
--and max(version)
;WITH PricesCTE AS
(
SELECT *,
ROW_NUMBER()OVER(PARTITION BY companyid,product ORDER BY version DESC) AS rn
FROM prices
WHERE GETDATE() BETWEEN [start] AND [end]
)
SELECT *
FROM PricesCTE
WHERE rn = 1
SQLFiddle Demo
First find the highest version per product for the desired date. Then join with your table to get that record.
select *
from
(
select companyid, product, max(version) as max_version
from prices
where getdate() between [start] and [end]
group by companyid, product
) this_date
inner join prices
on prices.companyid = this_date.companyid
and prices.product = this_date.product
and prices.version = this_date.max_version;
Here is the SQL fiddle: http://sqlfiddle.com/#!6/e0d4f/32.