MySql Fetch rows that have latest date - mysql

Here's the code:
SELECT tblitem.strItemCode, tblitem.strItemName, tblitemunit.strItemUnitName, tblvendor.strVendName, MAX(tblitemprice.dtmItemPasOf) AS Expr1,
tblitemprice.dblItemPAmount
FROM tblclassification INNER JOIN
tblitem ON tblclassification.strClasCode = tblitem.strItemClasCode INNER JOIN
tblitemprice ON tblitem.strItemCode = tblitemprice.strItemPItemCode INNER JOIN
tblitemunit ON tblitemprice.strItemPItemUnitCode = tblitemunit.strItemUnitCode INNER JOIN
tblvendor ON tblclassification.strClasCode = tblvendor.strVendClasCode AND tblitemprice.strItemPVendCode = tblvendor.strVendCode AND tblitem.deleted_at IS NULL
GROUP BY tblitem.strItemCode, tblitem.strItemName, tblitemunit.strItemUnitName, tblvendor.strVendName, tblitemprice.dblItemPAmount
And Here's the Result:
CODE NAME UNIT VENDOR DATE PRICE
ITEM101-Fudgee Bar-Piece-Imus Palengke 10/9/20165:03:32AM - 6.5
ITEM102-Yum Burger-Box-Jollibee Lumina Mall-10/9/2016 6:13:27 AM - 2500
ITEM102-Yum Burger-Piece-Jollibee Lumina Mall-10/9/2016 4:42:28 AM - 30
ITEM102-Yum Burger-Piece-Jollibee Lumina Mall-10/13/2016 12:37:31 PM- 35
ITEM102-Yum Burger Piece Jollibee Lumina Mall 10/14/2016 10:05:44 PM 40
What I want to happen is to fetch only the row with the latest price. Can someone help me please.
I want to fetch the Item101 and only the last row to ITEM102 since it is the latest.

If I understand correctly, you're looking for the last updated row price. It's easy to do so:
Order your data by their relevant timestamp in reversed order (ORDER BY <FIELD_NAME> DESC). From what I gather from your query and results, Expr1 is the latest date for a given price.
Only pick a single element (LIMIT 1). Since your data is already ordered in reverse chronological order, you're sure to pick the latest one.
The SQL for that would be
SELECT tblitem.strItemCode, tblitem.strItemName, tblitemunit.strItemUnitName, tblvendor.strVendName, MAX(tblitemprice.dtmItemPasOf) AS Expr1,
tblitemprice.dblItemPAmount
FROM tblclassification INNER JOIN
tblitem ON tblclassification.strClasCode = tblitem.strItemClasCode INNER JOIN
tblitemprice ON tblitem.strItemCode = tblitemprice.strItemPItemCode INNER JOIN
tblitemunit ON tblitemprice.strItemPItemUnitCode = tblitemunit.strItemUnitCode INNER JOIN
tblvendor ON tblclassification.strClasCode = tblvendor.strVendClasCode AND tblitemprice.strItemPVendCode = tblvendor.strVendCode AND tblitem.deleted_at IS NULL
GROUP BY tblitem.strItemCode, tblitem.strItemName, tblitemunit.strItemUnitName, tblvendor.strVendName, tblitemprice.dblItemPAmount
ORDER BY Expr1 DESC
LIMIT 1
Try it out !

Related

Get several data from SQL query based on different conditions

I have the following code:
SELECT DISTINCT m.solde_total_client
,c.client_nom
,co.contenant_nom
FROM `mouvement` m, `client` c, `contenant` co
WHERE c.client_id = m.client_id
AND co.contenant_id = m.contenant_id
ORDER BY m.movement_date DESC
LIMIT 1;
And I get as a result one total sold of one client. But I want to get one for each contenant for each client. (But it still need to be the last one by date)
I'm getting as a result:
And I want to get several result like that such as:
Leclerc | Geobox | 50
SuperU | Box | 40
...
sold_total_client is what the client as after a shipment, there is several shipment and the sold is updated at every move, so the last one by date is the actual sold. So I have to get the last move of every contenant of every client.
You could try using a subquery for max_date group by client_id, contenant_id
SELECT
m.solde_total_client,
m.`mouvement_date`,
c.client_nom,
co.contenant_nom
FROM
`mouvement` m
INNER JOIN
(SELECT
MAX(mouvement_date) max_date, client_id, contenant_id
FROM
`mouvement`
GROUP BY
client_id, contenant_id) t ON t.client_id = m.client_id
AND m.contenant_id = t.contenant_id
AND t.max_date = m.`mouvement_date`
INNER JOIN
`client` c ON c.client_id = m.client_id
INNER JOIN
`contenant` co ON co.contenant_id = m.contenant_id
ORDER BY
m.`mouvement_date`

How do I get the MIN value from two columns along with corresponding id?

My query does return the lowest price from the two columns (price_base, price_special) but it is not returning the correct store_id that corresponds to the lowest price found.
My Query:
SELECT grocery_item.id, grocery_item.category,
grocery_category.name AS cat, grocery_item.name AS itemName,
MIN( if( grocery_price.price_special>0,
grocery_price.price_base)) AS price,
grocery_price.store_id,
grocery_store.name AS storeName
FROM grocery_item
LEFT JOIN grocery_category ON
grocery_category.id=grocery_item.category
LEFT JOIN grocery_price
ON grocery_price.item_id = grocery_item.id
LEFT JOIN grocery_store
ON grocery_store.id=grocery_price.store_id
WHERE grocery_price.selection='no'
AND buy='yes'
GROUP BY grocery_price.item_id
ORDER BY store_id, grocery_item.category, grocery_item.name
Returns this:
ID category cat itemName price store_id storeName
92 3 Bread/Bakery Arnold Bread 2.14 1 Food Lion
But the grocery_price table holds this info:
item_id price_base price_special store_id
92 4.29 2.14 9
92 3.99 0.00 1
so the store_id I need to be returned is 9 (the storeName returned would NOT then be Food Lion)
EDIT: WORKING QUERY based on Uueerdo's comments (thank you!)
SELECT minP.item_id, gi.category, gc.name AS cat,
gi.name as itemName, gp.store_id,
gs.name AS storeName, minP.price
FROM
(SELECT p.item_id, MIN(IF(p.price_special >0,
p.price_special,p.price_base)) AS price
FROM grocery_item AS i
INNER JOIN grocery_price AS p ON (i.id = p.item_id)
WHERE i.buy = 'yes'
GROUP BY p.item_id) AS minP
INNER JOIN grocery_item AS gi ON minP.item_id = gi.id
INNER JOIN grocery_category AS gc on gi.category = gc.id
LEFT JOIN grocery_price AS gp
ON minP.price = IF(gp.price_special > 0,
gp.price_special,gp.price_base)
AND gp.item_id = gi.id
INNER JOIN grocery_store AS gs ON gp.store_id = gs.id
GROUP BY gi.id
ORDER BY gs.id, gi.category,gi.name
The values returned for non-grouped, non-aggregated fields are an (effectively) random selection from the values encountered with the grouped fields' values. Most RDBMS do not even consider such a query valid, and even newer versions of MySQL default to disallowing such queries.
In cases like yours, where you need the non-grouped value(s) associated with the aggregate result (min in this case); the aggregating query must be converted into a subquery, that can be joined back to the aggregated tables to find the source row(s) that correspond to the aggregated value.
Edit: Basically, you need to look at the problem slightly differently. You're currently finding the lowest price for an item and a store that item is listed for; you need to find the lowest price for an item, and use that to find the store(s) that have the item at that price.
This gets you the lowest price for item's marked "buy":
SELECT p.item_id, MIN(IF(p.price_special > 0,p.price_special,p.price_base)) AS price
FROM grocery_item AS i
INNER JOIN grocery_price AS p ON (i.id = p.item_id)
WHERE i.buy = 'yes'
GROUP BY p.item_id
You can then take that to get the rest of the results:
SELECT minP.item_id
, gi.name
, gi.category, gc.category_name AS cat, gi.Name as itemName, gi.buy
, gp.store_id, gp.name AS storeName
, minP.price
FROM ([the query above]) AS minP
INNER JOIN grocery_item AS gi ON minP.item_id = gi.id
INNER JOIN grocery_category AS gc on gi.category = gc.grocery_category_id
/* Guessing on this join since grocery_category_id
was not qualified with it's table name */
INNER JOIN grocery_price AS gp
ON minP.price = IF(gp.price_special > 0,gp.price_special,gp.price_base)
/* Alternatively: ON minP.price IN (gp.price_special, gp.price_base)
... though this could cause false positives if the minP.price is 0
from one store's base price being "free"
*/
INNER JOIN grocery_store AS gs ON gp.store_id = gs.id
;

MYSQL - JOIN table filter not working

I have four table each table connected with some id kindly see the below query how I'm getting
SELECT
tax_rates.name,
IF( products.tax_method = 0, 'Inclusive', 'Exclusive') AS type,
IF((SUM(purchases.grand_total) > 0),(SUM(purchases.grand_total)),(SUM(purchase_items .subtotal))) AS total_amount,
IF((SUM(purchases.order_tax) > 0),(SUM(purchases.order_tax)),SUM(purchase_items .item_tax)) AS tax_amount
FROM tax_rates
LEFT JOIN purchases ON purchases.order_tax_id = tax_rates.id
LEFT JOIN purchase_items ON purchase_items.tax_rate_id = tax_rates .id
LEFT JOIN products ON products.id = purchase_items.product_id
WHERE purchases.warehouse_id = 1
GROUP BY tax_rates.id, products.tax_method
ORDER BY tax_rates.name desc LIMIT 0, 10
The above query didn't return any result but if I remove WHERE purchases.warehouse_id = 1 then it display the result. I don't know where I'm doing the mistake. Kindly correct me.
Sorry to tell about this I'm try to get purchase order tax and purchase Item tax
in particular store and date
Output
name type total_amount tax_amount
VAT #20% Inclusive 11005.2000 1834.2000
VAT #10% Inclusive 165.0000 15.0000
No Tax Exclusive 204771.4000 0.0000
GST #6% Exclusive 7155.0000 405.0000
GST #6% Inclusive 7155.0000 405.0000
Thank you
Data type? purchases.warehouse_id = '1'?
You should not add the condition in where clause, when you are using the field of the left join table. so remove the where clause and use like below
LEFT JOIN purchases ON purchases.order_tax_id = tax_rates.id and purchases.warehouse_id = 1
If you try to add the left join table field in where clause it will become INNER JOIN. hence it may not display any rows according to your data.

Generate empty row for unused slots

I designed a db schema to hold patient appointments. Every hour is divided into equal 15 slots and the last two slots are always kept unused for emergency cases. When printing the appointment list, I need to have all the booked appointments along with empty row for 14 & 15th slot for each hour so receptionist can fill-in the unscheduled appointments by hand in the printed sheet.
appt_schedules:
id
slot_id
hour
scheduled_on
slots table - contains exactly 15 rows all the time.
id
start_time
end_time
The following query gives me the expected result except the empty row for 14 & 15th slot.
SELECT `appt_schedules`.* FROM `appt_schedules`
LEFT JOIN `slots` ON `appt_schedules`.`slot_id` = `slots`.`id`
WHERE `scheduled_on`='2015-04-17' LIMIT 10,10
I am also open to schema changes that can result in simple and efficient queries.
SELECT `appt_schedules`.*, `slots`.`slot_id` FROM `appt_schedules`
LEFT JOIN `slots` ON `appt_schedules`.`slot_id` = `slots`.`id`
WHERE `scheduled_on`='2015-04-17' and `slots`.`slot_id` between 1 and 15
Assuming of cours slots.slot_id holds the 15 equal alots as an int 1 to 15
Another way to write it a bit more optimized is:
SELECT `appt_schedules`.*, `slots`.`slot_id` FROM `appt_schedules`
LEFT JOIN `slots` ON `appt_schedules`.`slot_id` = `slots`.`id`
WHERE `scheduled_on`='2015-04-17' and `slots`.`slot_id` IS NOT NULL
Or even better:
SELECT `appt_schedules`.*, `slots`.`slot_id` FROM `appt_schedules`
JOIN `slots` ON `appt_schedules`.`slot_id` = `slots`.`id`
WHERE `scheduled_on`='2015-04-17'
****BEGIN REVISED EDIT****
If I understand correctly please try:
SELECT s.slot_id, aps.* FROM slots s
LEFT JOIN
(SELECT *, ROW_NUMBER()
over(PARTITION BY aps.slot_id
ORDER BY aps.slot_id
,aps.scheduled_on) AS RowId
FROM appt_schedules aps) aps
ON aps.slot_id = s.id
AND s.slot_id = aps.RowId
WHERE scheduled_on = '2015-04-17'
ORDER BY s.slot_id
Once again thanks for removing slos.slot_id....
select *
from slots s
left join appt_schedules as
on s.id = as.slot_id
where IFNULL(as.scheduled_on, '') in ('', '2015-04-17')

Mysql scenario - Get all tasks even if there is no entry?

I have three tables
Tasks with columns Taskid, Taskname
TaskAllocations with columns Taskid, EmpNum
TaskEntries with columns TaskId, EmpNum, WorkedDate, Hoursspent
Now I want to get all the task entries along a particular week. Here my problem is even if there is no Taskentry for a particular task I should get atleast a row with that TaskId, and Taskname with Hoursspent as Null in the query's resultset. I have been trying to get this with the below query.
SELECT A.TaskId,
B.TaskName,
SUM( C.HoursSpent ) as TotalHours ,
C.WorkedDate, C.Comments
FROM TaskAllocations A
LEFT OUTER JOIN TaskEntries C
ON A.TaskId = C.TaskId
AND A.EmpNum = C.EmpNum
INNER JOIN Tasks B
ON A.TaskId = B.TaskId
WHERE A.EmpNum =123456
AND C.WorkedDate
IN ('2010-01-17','2010-01-18','2010-01-19',
'2010-01-20','2010-01-21','2010-01-22','2010-01-23' )
GROUP BY A.TaskId, C.WorkedDate
ORDER BY A.TaskId,C.WorkedDate ASC ';
What I am getting for this SQL piece is if and only if there is an entry for a particular task id, then only i am getting a row for that. but what I want is to get atleast a row for each and every task that is available to a EmpNum. Even if I get one row for each TaskId and WorkedDate combination no issues. Please help me with this. Actual intention of this is to build a HTML two dimensional table with each task entry against date and task as shown below.
---------------------------------------------------------
TaskId TaskName Sun Mon Tue Wed Thu Fri Sat
---------------------------------------------------------
18 name1 2 3 4:30 3:30
19 name2
20 name3 4 2:30
22 name4 2:30
23 name5
24 name6 1:30 6
---------------------------------------------------------
So that this can be updated by the user for each year week. First I thought of group_concat but because of performance I am using normal group by query.
Note: for a particular taskid and workeddate there will be only one entry of hoursspent.
I have almost built the frontend. Please help me to get all task ids as above even if there is no entry. Do I need to use subquery.
don't user an inner join, use a left or right join, depending which values from which tables you want.
so:
SELECT *
FROM tasks t
LEFT JOIN taskentries te
ON t.id = te.id
which is the same statement as:
SELECT *
FROM tasksentries te
RIGHT JOIN tasks t
ON te.id = t.id
will get you all tasks, even if there is no taskentry
an inner join will only select rows when there are rows in both tables, left join selects all rows from the left (first) table and matching from the other row (if there is no such row, null will be the value of all columns). right join will do the oposite: select all rows from right (second) table and matching from left.
a LEFT JOIN b is the same as b RIGHT JOIN a
After rigorous testing of different options I came up with the below solution which will give the required results for me.
SELECT Final.TaskId,
Final.TaskName,
Tmp.HoursSpent AS TotalHours,
Tmp.WorkedDate
FROM (
SELECT A.TaskId, B.TaskName, A.EmpNum
FROM TaskAllocations A
INNER JOIN
Tasks B
ON ( A.TaskId = B.TaskId )
WHERE a.empnum = "333"
)Final
LEFT OUTER JOIN (
SELECT New.TaskId, New.EmpNum, New.WorkedDate, New.HoursSpent
FROM TaskEntries New
WHERE New.WorkedDate
IN
('2010-01-17','2010-01-18','2010-01-19',
'2010-01-20','2010-01-21','2010-01-22','2010-01-23' )
OR New.WorkedDate IS NULL
AND New.EmpNum = "333"
)Tmp
ON Tmp.TaskId = Final.TaskId
AND Tmp.EmpNum = Final.EmpNum
ORDER BY Final.TaskId, Tmp.WorkedDate ASC ;
The first query of mine in the question was not working as I was putting a condition on right table's column while doing Left Outer Join. Thanks to all for the support.