MySQL script triggers Error #1241 - mysql

I have the script below, which is supposed to get a price for an array of ID's that has been provided.
But it needs to get 1 price per ID, and the tricky part is, that I want to have the ability to have scheduled price updates.
This mean that it needs to take the price that is <= UTC_TIMESTAMP smaller or equal to the current time.
SELECT
`product_pricing`.`wo_id`,
`product_pricing`.`currency` AS price2_currency,
`product_pricing`.`price` AS price2,
`product_pricing`.`formula_id`,
`product_pricing`.`vat_calculated` AS price2_vat_calculated,
`product_pricing`.`vat_id`,
`product_pricing`.`timestamp_valid`,
`product_price_formulas`.`formula_id`,
`product_price_formulas`.`formula` price2_formula
FROM
`product_pricing`
LEFT JOIN `product_price_formulas`
ON `product_pricing`.`formula_id` = `product_price_formulas`.`formula_id`
WHERE
`product_pricing`.`wo_id` IN (
SELECT
`product_pricing`.`wo_id`,
`product_pricing`.`timestamp_valid`
FROM `product_pricing`
WHERE
`product_pricing`.`wo_id`
IN ('015724', '028791', '015712', '015715', '015717', '039750', '028791')
AND `product_pricing`.`timestamp_valid` <= UTC_TIMESTAMP
ORDER BY `product_pricing`.`timestamp_valid` DESC
)
Is this possible?
Sample data: Current output
——————————————————————————————————————————————————————————————————
| wo_id | price2 | timestamp_valid
——————————————————————————————————————————————————————————————————
| 028791 | 8000 | 2018-03-20 19:55:41
| 028791 | 6000 | 2018-04-01 19:55:41
| 028791 | 4000 | 2018-04-20 19:55:41
| 015724 | 3000 | 2018-04-18 19:55:41
| 015724 | 1500 | 2018-03-01 19:55:41
....
Wanted output:
——————————————————————————————————————————————————————————————————
| wo_id | price2 | timestamp_valid
——————————————————————————————————————————————————————————————————
| 028791 | 6000 | 2018-04-01 19:55:41
| 015724 | 1500 | 2018-03-01 19:55:41

I guess your issue is on the IN clause.
You select two field in IN clause.
EDIT
You need to self join a subquery by wo_id and Max timestamp_valid.
SELECT
`product_pricing`.`wo_id`,
`product_pricing`.`currency` AS price2_currency,
`product_pricing`.`price` AS price2,
`product_pricing`.`formula_id`,
`product_pricing`.`vat_calculated` AS price2_vat_calculated,
`product_pricing`.`vat_id`,
`product_pricing`.`timestamp_valid`,
`product_price_formulas`.`formula_id`,
`product_price_formulas`.`formula` price2_formula
FROM
`product_pricing`
LEFT JOIN `product_price_formulas` ON `product_pricing`.`formula_id` = `product_price_formulas`.`formula_id`
INNER JOIN
(
SELECT
`product_pricing`.`wo_id`,
MAX(`timestamp_valid`) AS MaxDate
FROM `product_pricing`
WHERE
`product_pricing`.`timestamp_valid` <= UTC_TIMESTAMP
GROUP BY
`product_pricing`.`wo_id`
)as temp ON temp.wo_id = `product_pricing`.`wo_id` AND temp.MaxDate = `product_pricing`.`timestamp_valid`
WHERE
`product_pricing`.`wo_id` IN ('015724', '028791', '015712', '015715', '015717', '039750', '028791')

I think you want something like this:
SELECT pp.*, ppf.formula_id, ppf.formula as price2_formula
FROM product_pricing pp LEFT JOIN
product_price_formulas ppf
ON pp.formula_id = ppf.formula_id
WHERE (pp.wo_id, pp.timestamp_valid) IN
(SELECT pp2.wo_id, MAX(pp2.timestamp_valid)
FROM product_pricing pp2
WHERE pp2.wo_id IN ('015724', '028791', '015712', '015715', '015717', '039750', '028791') AND
pp2.timestamp_valid <= UTC_TIMESTAMP
);
The ORDER BY makes no sense in the subquery, so this is my best guess as to what you want.
I left this with your structure of using IN, but I would use a correlated subquery and =:
WHERE pp.timestamp_valid = (SELECT MAX(pp2.timestamp_valid)
FROM product_pricing pp2
WHERE pp2.wo_id = pp.wo_id AND
pp2.timestamp_valid <= UTC_TIMESTAMP
) AND
pp2.wo_id IN ('015724', '028791', '015712', '015715', '015717', '039750', '028791');

You could JOIN product_pricing with a derived result set of the most recent valid_timestamp records.
If we ignore the product_pricing_formula table for now (since you didn't include it in your specimen data and result) that would give.
SELECT
p.`wo_id`,
p.`price` AS price2,
p.`timestamp_valid`
FROM `product_pricing` p
JOIN (SELECT wo_id, MAX(timestamp_valid) AS max_valid_ts
FROM `product_pricing`
WHERE `timestamp_valid` <= UTC_TIMESTAMP
GROUP BY wo_id) d
ON (d.wo_id = p.wo_id AND d.max_valid_ts = p.timestamp_valid)
WHERE p.`wo_id` IN (015724, 028791);
Try it on Sqlfiddle

Related

Get current date Sum of two column and Last Row of one Column using Id - MYSQL

I have a table A named patientinfo as shown:
and table b named as tblpayment is as follows:
Now, What I want is to get PatientId and PatientName From Table A JOINING today's paymentDate of Table B and SUM(paymentTotal),SUM(paymentPaid) But LAST row OF paymentRemaining.
In Simple words, I want all the today's patients with SUM of paymentTotal and Sum of paymentPaid but LAST row of paymentRemaining.
Graphically, what I want should be like:
patientId paymentTotal paymentPaid paymentRemaining
252 123500 118500 5000
253 60000 55000 5000
254 17500 17500 0
258 5800 0 5800
NOTE: The record should be of current date.
Any Help?
What I have done so far:
SELECT a.patientId , a.patientName, b.paymentTotal , b.paymentPaid , b.paymentRemaining FROM
patientinfo a
inner join
(
SELECT patienId , SUM(paymentTotal) as paymentTotal ,SUM(paymentPaid) as paymentPaid,
MAX(paymentRemaining) as paymentRemaining
FROM tblpayment WHERE paymentDate LIKE '%$date%' GROUP BY patienId
)b
on a.patientId = b.patienId
Everything is fine, But the error in this query is that it gives me the very first value of column paymentRemaining. Whereas, I want the last value of payment and it is giving me the MAX value. What should I replace this Max with?
EDIT:
A bit mistake in my question. I don't want MAX of paymentRemaining, but LAST row of paymentRemaining of respective patientId.
You just need MIN instead of MAX with LEFT JOIN:
SELECT DISTINCT
t.patientId,
b.paymentTotal ,
b.paymentPaid , b.paymentRemaining
FROM tblpayment AS t
LEFT JOIN patientinfo a ON t.patientId = a.patientId
LEFT join
(
SELECT patientId , SUM(paymentTotal) as paymentTotal,
SUM(paymentPaid) as paymentPaid,
MIN(paymentRemaining) as paymentRemaining
FROM tblpayment
GROUP BY patientId
) b on t.patientId = b.patientId
demo
This will give you exactly what you want:
| patientId | paymentTotal | paymentPaid | paymentRemaining |
|-----------|--------------|-------------|------------------|
| 252 | 123500 | 118500 | 5000 |
| 253 | 60000 | 55000 | 5000 |
| 254 | 17500 | 17500 | 0 |
| 258 | 5800 | 0 | 5800 |
Update:
If you want the last row, then it will be the one with the latest date for each patientid. Then try this:
SELECT DISTINCT
t.patientId,
b.paymentTotal ,
b.paymentPaid ,
t.paymentRemaining
FROM
(
a.patientId, paymentRemaining, paymentDate
FROM tblpayment AS t
LEFT JOIN patientinfo a ON t.patientId = a.patientId
) AS t
INNER join
(
SELECT patientId , SUM(paymentTotal) as paymentTotal,
SUM(paymentPaid) as paymentPaid
FROM tblpayment
GROUP BY patientId
) b on t.patientId = b.patientId
INNER JOIN
(
SELECT patientId, MAX(paymentDate) AS LatestDate
FROM tblpayment
GROUP BY patientId
) AS s ON s.patientId = t.patientId AND t.paymentDate = s.LatestDate

How to get data from a table even when count(row) is zero? please see the description for more details and the query?

table one
id mandal_name
1 mandal1
2 mandal2
3 mandal3
table address
id mandal_name date
1 mandal1 2017-07-11 12:34:11
2 mandal1 2017-07-11 12:54:45
3 mandal1 2017-07-11 12:23:23
SELECT count(id) as yesterday_count, mandal FROM address WHERE date(date) = '2017-07-11'
Result obviously
3 , mandal1
Expecting result
3 , mandal1
0 , mandal2
0 , mandal3
...
The key is to use an OUTER JOIN - LEFT JOIN in this case.
You can either do
SELECT m.mandal_name, COUNT(a.id) AS yesterday_count
FROM table_one m LEFT JOIN address a
ON m.mandal_name = a.mandal_name
AND a.date >= '2017-07-11'
AND a.date < '2017-07-12'
GROUP BY m.mandal_name;
or
SELECT m.mandal_name, COALESCE(count, 0) AS yesterday_count
FROM table_one m LEFT JOIN (
SELECT mandal_name, COUNT(*) AS count
FROM address
WHERE date >= '2017-07-11'
AND date < '2017-07-12'
) a
ON m.mandal_name = a.mandal_name;
Here is a SQLFiddle demo
Output
| mandal_name | yesterday_count |
|-------------|-----------------|
| mandal1 | 3 |
| mandal2 | 0 |
| mandal3 | 0 |
Further reading - A Visual Explanation of SQL Joins
On a side note - don't use DATE(date) as it makes it impossible to use an index on date column effectively causing a full table scan.
you can query it like this:
SELECT A.mandal_name,IFNULL(COUNT(*),0)
FROM one A
LEFT JOIN address B ON A.mandal_name = B.mandal_name
WHERE DATE(B.date) = '2017-07-11'
GROUP BY A.mandal_name
just substitute your table name and columns to get the result

MYSQL INNER JOIN unexpected result

I'm having a problem on my MySQL Inner join. My INNER JOIN doesn't give me my desired result. I have Table1 that contains the TrackNo only then Table2 contains the details of Table1 per trackNo.
>> Table Structure:
>> SQL Code:
SELECT tr.trackNo AS 'TrackNo',
trD.Status,
MAX(trD.DatePosted) AS `Date/Time`
FROM Tracking AS tr
INNER JOIN TrackingDetails AS trD
ON tr.trackNo = trD.trackNo
WHERE tr.ClientID='client01'
AND trD.trackNo IN ('xx000001','xx000002','xx000003')
AND trD.DatePosted IS NOT NULL
AND trD.Status IN (
'Received',
'Logged',
'Prepped',
'Analyzed',
'Reviewed',
'Final Report',
'Invoiced')
GROUP BY tr.trackNo
ORDER BY tr.trackNo ASC
Here's the result query above:
As you can see the query result image above is correct except for Status column.Where did I go wrong on my SQL Query? Did I miss something?
>> Desired output:
+----------+----------+---------------------+
| TrackNo | Status | Date/Time |
+==========+==========+=====================+
| xx000001 | Logged | 2015-03-09 17:53:14 |
+----------+----------+---------------------+
| xx000002 | Prepped | 2014-08-15 17:19:00 |
+----------+----------+---------------------+
| xx000003 | Analyzed | 2014-10-10 11:12:00 |
+----------+----------+---------------------+
Thanks in advance!
This should gives you the correct result:
select * from TrackingDetails as a join (
SELECT tr.trackNo AS 'TrackNo',
MAX(trD.DatePosted) AS 'Date_Time'
FROM Tracking AS tr
INNER JOIN TrackingDetails AS trD
ON tr.trackNo = trD.trackNo
WHERE tr.ClientID='client01'
AND trD.trackNo IN ('xx000001','xx000002','xx000003')
AND trD.DatePosted IS NOT NULL
AND trD.Status IN (
'Received',
'Logged',
'Prepped',
'Analyzed',
'Reviewed',
'Final Report',
'Invoiced')
GROUP BY tr.trackNo
ORDER BY tr.trackNo ASC
) as x on x.TrackNo = a.trackNo and a.DatePosted = x.'Date_Time'
If you use group by in mysql it is not specified wich values you get from columns which are not in aggregation function or in the group by statement. In most other DBMS it is not allowed to select such columns.

How to avoid two results of the same row in join

I have three tables actually on virturt mart table one is orders, another is item & one is order_user_info
to get the user first name i need to join order_user_info table
but when i join it shows the result info double, below i have mentioned the query & result please guide how can avoid double result
*FOR JOIN FIRST NAME I AM USING BELOW MENTIONED QUERY *
LEFT JOIN `urbanite_virtuemart_order_userinfos` as Uinfo ON Uinfo.virtuemart_order_id=i.virtuemart_order_id
*COMPLETE QUERY *
SELECT SQL_CALC_FOUND_ROWS o.created_on AS intervals, CAST( i.`created_on` AS DATE ) AS created_on, Uinfo.`first_name`, o.`order_number`, SUM(DISTINCT i.product_item_price * product_quantity) as order_subtotal_netto, SUM(DISTINCT i.product_subtotal_with_tax) as order_subtotal_brutto, COUNT(DISTINCT i.virtuemart_order_id) as count_order_id, SUM(i.product_quantity) as product_quantity FROM `urbanite_virtuemart_order_items` as i
LEFT JOIN `urbanite_virtuemart_orders` as o ON o.virtuemart_order_id=i.virtuemart_order_id
LEFT JOIN `urbanite_virtuemart_order_userinfos` as Uinfo ON Uinfo.virtuemart_order_id=i.virtuemart_order_id AND Uinfo.created_on = i.created_on AND Uinfo.virtuemart_user_id = o.virtuemart_user_id
WHERE (`i`.`order_status` = "S") AND i.virtuemart_vendor_id = "63" AND DATE( o.created_on ) BETWEEN "2013-06-01 05:00:00" AND "2013-06-30 05:00:00"
GROUP BY intervals
ORDER BY created_on DESC LIMIT 0, 400
result i am getting with out join like below
intervals | Created_on | order_no | order_subtotalnetto | order_subtotalbruto | count_order_id | product_quantity
2013-06-12 09:47:16 |2013-06-12 | 43940624 | 200.00000 | 200.00000 | 1 | 2
result i am getting with join for firstname like below
intervals | Created_on | order_no | f_name | order_subtotalnetto | order_subtotalbruto | count_order_id | product_quantity
2013-06-12 09:47:16 |2013-06-12 | Fatin Bokhari | 43940624 | 200.00000 | 200.00000 | 1 | 4
see in with out join for first name it show product_quantity = 2 but when i join it shows the value double, i tried distinct but cant go this way as it show the product quantity = 1 every time
Kindly need rescue!
oh actually the rows comes twice in a urbanite_virtuemart_order_userinfos table so i used where clause & it works
WHERE (`i`.`order_status` = "S") AND i.virtuemart_vendor_id = "63" AND DATE( o.created_on ) BETWEEN "2013-06-01 05:00:00" AND "2013-06-30 05:00:00" AND Uinfo.`address_type` = 'BT'

difficulties getting a 3 table join to return expected results

I'm having some difficulty getting to the bottom of this sql query.
Tables:
--Tickets-- --Finance-- --Access--
id_tickets id_finance id_access
name_tickets id_event id_event
cat_tickets id_tickets id_tickets
sold_finance scan_access
Finance and Access both contain a row for multiple of each ticket type as listed in tickets.
and I'm trying to get:
cat_tickets | total_sold | total_scan
-------------------------------------
single | 3043 | 2571
season | 481 | 292
comp | 114 | 75
-------------------------------------
total | 3638 | 2938
The closest I've been to the result I've used:
SELECT tickets.cat_tickets, COALESCE(SUM(finance.sold_finance), 0) AS total_sold, COALESCE(SUM(access.scan_access), 0) AS total_scan
FROM finance INNER JOIN tickets ON finance.id_tickets = tickets.id_tickets
INNER JOIN access ON access.id_tickets = tickets.id_tickets
WHERE access.id_event = 235 AND finance.id_event = access.id_event
GROUP BY tickets.cat_tickets
ORDER BY tickets.cat_tickets DESC
but that just returns:
cat_tickets | total_sold | total_scan
-------------------------------------
single | 4945 | 4437
season | 954 | 599
comp | 342 | 375
-------------------------------------
total | 6241 | 5411
Any ideas where I could be going wrong?
Thanks!
The problem is the relation between access and finance tables, you have to join them. Even if you LEFT JOIN the table the predicate finance.id_event = access.id_event will make it INNER JOIN. As a work around, use UNION like this:
SELECT
tickets.cat_tickets,
SUM(CASE WHEN a.Type = 'f' THEN num ELSE 0 END) AS total_sold,
SUM(CASE WHEN a.Type = 'a' THEN num ELSE 0 END) AS total_scan
FROM tickets
LEFT JOIN
(
SELECT 'f' Type, id_tickets, sold_finance num
FROM finance f
WHERE id_event = 1
UNION ALL
SELECT 'a', id_tickets, scan_access
FROM access
WHERE id_event = 1
) a ON a.id_tickets = tickets.id_tickets
GROUP BY tickets.cat_tickets;
SQL Fiddle Demo
Although I am fully clear on what you want, just try this query if the result of this is what you are expecting.
SELECT tickets.cat_tickets, COALESCE(SUM(finance.sold_finance), 0) AS total_sold, COALESCE(SUM(access.scan_access), 0) AS total_scan
FROM finance LEFT JOIN tickets ON finance.id_tickets = tickets.id_tickets
LEFT JOIN access ON access.id_tickets = tickets.id_tickets
WHERE access.id_event = 235
GROUP BY tickets.cat_tickets
ORDER BY tickets.cat_tickets DESC
Disclaimer: This query is not tested due to incomplete data on the question.
SELECT z.Cat_tickets,
COALESCE(x.total_sold,0) total_sold,
COALESCE(y.total_scan,0) total_scan
FROM tickets z
LEFT JOIN
(
SELECT a.id_tickets,
a.cat_tickets,
SUM(b.sold_finance) total_sold
FROM tickets a
INNER JOIN finance b
ON a.id_tickets = b.id_tickets
WHERE id_event = 235
GROUP BY a.id_tickets, a.cat_tickets
) x ON z.id_tickets = x.id_tickets
LEFT JOIN
(
SELECT aa.id_tickets,
aa.cat_tickets,
SUM(bb.scan_access) total_scan
FROM tickets aa
INNER JOIN Access bb
ON aa.id_tickets = bb.id_tickets
WHERE id_event = 235
GROUP BY aa.id_tickets, aa.cat_tickets
) y ON z.id_tickets = y.id_tickets