I have a table with columns ID, WorkingDate and AmountReceived where data is show as
ID WorkingDate AmountReceived
-------------------------------------
1 13/April/2021 201999.01
2 14/Arpil/2021 1099.02
Now, I am trying to show it like
13/April/2021 14/April/2021 15/April/2021
--------------------------------------------------
201999.01 1099.02 102.09
I tried this
select AmountReceived, WorkingDate
from Orders o
select distinct o.WorkingDate, sum(AmountReceived) over (partition by WorkingDate) as total
from Orders o
group by WorkingDate, AmountReceived
But it throws an aggregate error.
Using PIVOT operator, you can achieve what you want
select *
from
(
select o.WorkingDate, o.AmountReceived
from Orders o
) o
pivot
(
sum(AmountReceived)
for WorkingDate in ([2021-04-13], [2021-04-14], [2021-04-15])
) p
Related
I have a table called products and I would like to get all my products with same asin inside one row and concat their skus in one column I came up with something like this but I have problem with order by sku and other columns that are not inside group by. Is there any solution?
my sql:
SELECT prod.asin, string_agg(p.sku,', ') AS skus,
SUM(p.amazon_inv_available) AS amazon_available_inv,
SUM(p.amazon_inv_total) AS amazon_total_inv
FROM (
SELECT id, asin, sku, amazon_inv_available, amazon_inv_total
FROM products
WHERE store_id IN (12, 10, 11)
ORDER BY sku
) AS prod
LEFT JOIN products AS p ON prod.asin = p.asin
GROUP by prod.asin
dbfiddle
Desired result when order by prod.sku
order by prod.sku DESC
You can order by inside string_agg(sku,', ' order by sku) remove order by from your subquery
You can add ORDER BY to STRING_AGG() to specify the ordering of the concatenated values.
For example:
SELECT
asin,
string_agg(sku,', ' order by id) AS skus,
SUM(amazon_inv_available) AS amazon_available_inv,
SUM(amazon_inv_total) AS amazon_total_inv
FROM products
WHERE store_id IN (12, 10, 11)
GROUP by asin
ORDER BY amazon_available_inv
Result:
asin skus amazon_available_inv amazon_total_inv
----- ----------- --------------------- ----------------
B HH, QW 200 400
A AC, TT, DD 300 600
See db<>fiddle.
I think I found the solution. I used my query as subquery:
SELECT * FROM
(SELECT prod.asin, string_agg(p.sku,', ' ORDER BY p.sku) AS skus,
SUM(p.amazon_inv_available) AS amazon_available_inv,
SUM(p.amazon_inv_total) AS amazon_total_inv
FROM (SELECT id, asin, sku, amazon_inv_available, amazon_inv_total
FROM products WHERE store_id IN(
10,11,12)) AS prod
LEFT JOIN
products AS p
ON prod.asin = p.asin
GROUP by prod.asin) AS res
ORDER BY skus
I want to select the ID of the Table Products with the lowest Price Grouped By Product.
ID Product Price
1 123 10
2 123 11
3 234 20
4 234 21
Which by logic would look like this:
SELECT
ID,
Min(Price)
FROM
Products
GROUP BY
Product
But I don't want to select the Price itself, just the ID.
Resulting in
1
3
EDIT: The DBMSes used are Firebird and Filemaker
You didn't specify your DBMS, so this is ANSI standard SQL:
select id
from (
select id,
row_number() over (partition by product order by price) as rn
from orders
) t
where rn = 1
order by id;
If your DBMS doesn't support window functions, you can do that with joining against a derived table:
select o.id
from orders o
join (
select product,
min(price) as min_price
from orders
group by product
) t on t.product = o.product and t.min_price = o.price;
Note that this will return a slightly different result then the first solution: if the minimum price for a product occurs more then once, all those IDs will be returned. The first solution will only return one of them. If you don't want that, you need to group again in the outer query:
select min(o.id)
from orders o
join (
select product,
min(price) as min_price
from orders
group by product
) t on t.product = o.product and t.min_price = o.price
group by o.product;
SELECT ID
FROM Products as A
where price = ( select Min(Price)
from Products as B
where B.Product = A.Product )
GROUP BY id
This will show the ID, which in this case is 3.
This works perfectly until an order comes in where the stationID is not =2. My logic would be that sql searches where both conditions meet and display those results and not look where timeplaced is max then if stationid does not =2 display nothing which is what its doing.
SELECT OrderNo
FROM Orders
WHERE TimePlaced = (SELECT max(TimePlaced) FROM Orders)
AND StationID=2
Add your condition into the inner select too
SELECT OrderNo
FROM Orders
WHERE TimePlaced =
(
SELECT max(TimePlaced)
FROM Orders
WHERE StationID=2
)
AND StationID=2
But if you do not want to add the condition twice, then just "link" the inner select with the outer:
SELECT OrderNo
FROM Orders O
WHERE TimePlaced =
(
SELECT max(TimePlaced)
FROM Orders
WHERE StationID=O.StationID
)
AND StationID=2
Another way you could try would be with using a CTE and ROW_NUMBER:
;WITH OrdersCTE AS
(
SELECT *,
ROW_NUMBER() OVER(PARTITION BY StationID ORDER BY TimePlaced Desc) AS rn
FROM Orders
)
SELECT *
FROM OrdersCTE
WHERE rn = 1
AND StationID = 2
I have a table ProductDeliveryModes as:
ProductId DeliveryId
P101 D1
P101 D2
P101 D3
P102 D1
P102 D2
P102 D3
P103 D1
I need to get products which support all delivery modes (D1, D2, D3). From looking at the table the products should be: P101 and P102.
The query that I formed to get the solution is:
SELECT ProductId
FROM (SELECT DISTINCT ProductId,
DeliveryId
FROM ProductDeliveryModes) X
WHERE X.DeliveryId IN ( 'D1', 'D2', 'D3' )
GROUP BY ProductId
HAVING COUNT(*) = 3
The problem that I see in my solution is that one should know the count of the total number of delivery modes. We could make the count dynamic by getting the count from Sub-query.
Is there a better solution ?
I believe you can use DISTINCT with COUNT function to get the same result:
SELECT [ProductID]
FROM ProductDeliveryModes
GROUP BY [ProductID]
HAVING COUNT(DISTINCT [DeliveryId]) = 3
Check the example.
You can simple store the distinct delivery count in a variable and used it. If you need to do this in a single query, this is one of the possible ways:
WITH CTE (DeliveryCount) AS
(
SELECT COUNT(DISTINCT [DeliveryID])
FROM DataSource
)
SELECT [ProductID]
FROM DataSource
CROSS APPLY CTE
GROUP BY [ProductID]
,CTE.DeliveryCount
HAVING COUNT(DISTINCT [DeliveryID]) = DeliveryCount
See the example.
you can use this below query for better performance.
;WITH CTE_Product
AS
(
SELECT DISTINCT ProductID
FROM ProductDeliveryModes
),CTE_Delivery
AS
(
SELECT DISTINCT DeliveryId
FROM ProductDeliveryModes
)
SELECT *
FROM CTE_Product C
WHERE NOT EXISTS
(
SELECT 1
FROM CTE_Delivery D
LEFT JOIN ProductDeliveryModes T ON T.DeliveryId = D.DeliveryId AND T.ProductId=C.ProductId
WHERE T.ProductID IS NULL
)
You can modify your query just a bit to get the actual count of distinct delivery methods:
SELECT ProductID
FROM ProductDeliveryModes
GROUP BY ProductID
HAVING COUNT(*) =
(SELECT COUNT (DISTINCT DeliveryId) FROM ProductDeliveryModes)
I have a SQL Query giving me a list of double records in my database.
select periodid, itemid from periodscore
group by periodid, itemid
having count(*) > 1
This works as expected, but now I would like to retrieve additional fields of these records (such as date last updated etc). So I tried:
select * from periodscore where periodscoreid in
(select periodscoreid from periodscore
group by periodid, itemid
having count(*) > 1)
Of course this doesn't work and gives me the error:
Column 'periodscore.PeriodScoreID' is
invalid in the select list because it
is not contained in either an
aggregate function or the GROUP BY
clause.
How can I retrieve the extra fields in this query?
select ps.*
from periodscore ps
inner join (
select periodid, itemid
from periodscore
group by periodid, itemid
having count(*) > 1
) psm on ps.periodid = psm.periodid and ps.itemid = psm.itemid
select p1.* from periodscore p1 JOIN
(select periodid, itemid from periodscore
group by periodid, itemid
having count(*) > 1) p2
ON (p1.periodId = p2.periodId
AND p1.itemid = p2.itemid)
if periodid or item have null values then
select p1.* from periodscore p1 JOIN
(select periodid, itemid from periodscore
group by periodid, itemid
having count(*) > 1) p2
ON (IFNULL(p1.periodId,0) = IFNULL(p2.periodId,0))
AND IFNULL(p1.itemid,0) = IFNULL(p2.itemid,0))