MYSQL INNER JOIN unexpected result - mysql

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.

Related

MySQL script triggers Error #1241

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

SQL Query to compare two values which are in the same column but returned by two different set of queries

I have a table similar to the one shown below.
-----------------------------
JOB ID | parameter | result |
-----------------------------
1 | xyz | 10 |
1 | abc | 15 |
2 | xyz | 12 |
2 | abc | 8 |
2 | mno | 20 |
-----------------------------
I want the result as shown below.
parameter | result 1 | result 2 |
----------------------------------
xyz | 10 | 12 |
mno | NULL | 20 |
abc | 15 | 8 |
----------------------------------
My goal is to have a single table which can compare the result values of two different jobs. It can be two or more jobs.
you want to simulate a pivot table since mysql doesn't have pivots.
select
param,
max(case when id = 1 then res else null end) as 'result 1',
max(case when id = 2 then res else null end) as 'result 2'
from table
group by param
SQL FIDDLE TO PLAY WITH
If you are using MySQL there are no "outer join" need to use union right and left join:
Something like:
select t1.parameter, t1.result 'Result 1', t2.result 'Result 2' from
table as t1 left join table as t2
on t1.parameter=t2.parameter
where t1.'JOB ID' = 1 and t2.'JOB ID' = 2
union
select t1.parameter, t1.result 'Result 1', t2.result 'Result 2' from
table as t1 right join table as t2
on t1.parameter=t2.parameter
where t1.'JOB ID' = 1 and t2.'JOB ID' = 2
If the SQL with full outer join will make it more easier:
select t1.parameter, t1.result 'Result 1', t2.result 'Result 2' from
table as t1 outer join table as t2
on t1.parameter=t2.parameter
where t1.'JOB ID' = 1 and t2.'JOB ID' = 2
In Postgres, you can use something like:
select parameter, (array_agg(result))[1], (array_agg(result))[2] from my_table group by parameter;
The idea is: aggregate all the results for a given parameter into an array of results, and then fetch individual elements from those arrays.
I think that you can achieve something similar in MySQL by using GROUP_CONCAT(), although it returns a string instead of an array, so you cannot easily index it. But you can split by commas after that.
select q1.parameter, q2.result as r1, q3.result as r2
from
(select distinct parameter from temp2) q1
left join (select parameter, result from temp2 where job_id = 1) q2
on q1.parameter = q2.parameter
left join (select parameter, result from temp2 where job_id = 2) q3
on q1.parameter = q3.parameter;
It works, but it's not efficient. Still, since I'm gathering you are trying to solve something more complex than what's presented, this might help form your general solution.
While I'm at it, here's a slightly cleaner solution:
select distinct q1.parameter, q2.result as r1, q3.result as r2
from
temp2 q1
left join (select parameter, result from temp2 where job_id = 1) q2
on q1.parameter = q2.parameter
left join (select parameter, result from temp2 where job_id = 2) q3
on q1.parameter = q3.parameter;

PHP MySQL SELECT newest entry grouped by an ID and ordered by timestamp

I am working on an problem regarding Selecting data from two MySQL tables.
First table holds messages | messages | (id, msg_group_id, to_user_id, from_user_id, datetime)
Second table holds user data | profiles | (user_id, name, firstname, ...)
ATM it works the way, that I can select ALL messages with a certain 'to_id' and by adding a JOIN statement getting the name and firstname of the user who sends the message.
My problem now is that I can not figure out a way to ONLY select the newest message of a certain msg_group_id.
I already tried GROUP BY msg_group_id combined with ORDER BY datetime DESC.
But that only throws the very first entry in message table. But I want to last one. :-)
I hope you can help me. :-)
My actual SQL statement:
SELECT LEFT(messages.message, 10) AS message,
`messages`.`msg_group_id`,
`messages`.`datetime`,
`profiles`.`name`,
`profiles`.`firstname`
FROM `messages`
LEFT JOIN `profiles`
ON `messages`.`from_user_id` = `profiles`.`user_id`
WHERE `to_user_id` = '2'
ORDER BY `datetime` DESC
LIMIT 20;
Thanks in Advance
Sample INPUT:
[messages]
|id|msg_group_id|to_user_is|from_user_id|message |datetime|
0 | 1 | 1 | 2 | Hello World1 | 2015-12-21 10:42:00
1 | 1 | 1 | 2 | Hello World2 | 2015-12-21 10:43:00
2 | 1 | 1 | 2 | Hello World3 | 2015-12-21 10:44:00
[profiles]
user_id|name |firstname|
1 | Test | User
2 | Thanks | Worldname
Result (what I don't want)
message|msg_group_id|datetime|name|firstname
Hello World1 | 1 | 2015-12-21 10:42:00 | Thanks | Worldname
Result (what I want)
message|msg_group_id|datetime|name|firstname
Hello World3 | 1 | 2015-12-21 10:44:00 | Thanks | Worldname
May be this query can help:
SELECT m.message, m.msg_group_id, m.datetime, u.name, u.firstname
FROM message as m, profiles as u
WHERE m.from_user_id = u.user_id
GROUP BY m.msg_group_id
ORDER BY m.datetime DESC
Or use INNER JOIN
SELECT m.message, m.msg_group_id, m.datetime, u.name, u.firstname
FROM message as m
INNER JOIN profiles as u ON m.from_user_id = u.user_id
GROUP BY m.msg_group_id
ORDER BY m.datetime DESC
I guess I solved the Problem with the help of another thread:
https://stackoverflow.com/a/1313140/4493030
My SQL Statement as follows:
SELECT `messages`.*, `profiles`.`nick_name`
FROM `messages`
LEFT JOIN `profiles`
ON `messages`.`from_user_id` = `profiles`.`user_id`
INNER JOIN
(SELECT konversation_id, MAX(id) AS maxid FROM messages
WHERE messages.to_user_id = 2
GROUP BY konversation_id) AS b
ON messages.id = b.maxid
WHERE `to_user_id` = '2'
ORDER BY `datetime` DESC
LIMIT 20;
Thanks to all of you who tried to help.
I found a way to tight it down
SELECT messages.to_user_id, messages.msg_group_id, MAX(messages.id) AS maxid, messages.from_user_id, profiles.name
FROM messages
LEFT JOIN profiles
ON messages.from_user_id = profiles.user_id
WHERE messages.to_user_id = 2
GROUP BY msg_group_id

Select values based on other value within joined tables SQL

I would like to ask for help for an SQL request that give me values from two tables.
As an example I have one Table orders und one table processing.
I would like to make an report of the orders and the state of processing.
table orders
id | status | div
-------------------
1 | wating_r | div1
2 | closed | div2
3 | closed | div3
-
table processing:
id | order_id | type | date
----------------------------------------
1 | 2 | send_request | 15.01.15
2 | 2 | send_invoice | 30.01.15
3 | 1 | send_request | 01.02.15
4 | 3 | send_request2 | 10.02.15
5 | 3 | send_invoice | 15.02.15
what I would like to get:
order_id | status | date_request | date_request2 | date_invoice
--------------------------------------------------------------------------------
1 | waiting_r | 01.02.15 | NULL | NULL
2 | closed | 15.01.15 | NULL | 30.01.15
3 | closed | NULL | 10.02.15 | 15.02.15
my solution:
select orders.id as order_id, orders.status, IF(processing.type='send_invoice',date_format(processing.date, '%Y-%m-%d'), NULL) as date_invoice, IF(processing.type='send_request',date_format(processing.date, '%Y-%m-%d'), NULL) as date_request, IF(processing.type='send_request2',date_format(processing.date, '%Y-%m-%d'), NULL) as date_request2
from orders
inner join processing on orders.id = processing.order_id
where
case
when orders.status='closed' then processing.type='send_invoice'
when orders.status='waiting_r' then processing.type='send_request'
when orders.status='waiting_2'then processing.type='send_request2'
end
This works fine but with this IF statements I doesn't become the dates from the requests when an invoice was sent - I only get the date of the invoice.
Instead of the case request I tried the following but in this case I have more than one line for every order. When I tried to "group by" I have mixed data.
where
processing.type in ('send_invoice', 'send_request', 'completion_request_send')
You need to left-join the second table to the first three times, like so.
SELECT o.id AS order_id, o.status,
p1.date AS date_request,
p2.date AS date_request2,
p3.date AS date_invoice
FROM orders o
LEFT JOIN processing p1 ON o.id = p1.order_id AND p1.type='send_request'
LEFT JOIN processing p2 ON o.id = p2.order_id AND p2.type='send_request2'
LEFT JOIN processing p3 ON o.id = p3.order_id AND p3.type='send_invoice'
ORDER BY 1,2
This left-join with an id-matching criterion and the specific type choice pulls out the rows you need for each column. Left, as opposed to inner, join, allows the missing values to be shown as null.
Here it is, working. http://sqlfiddle.com/#!9/b8c74/5/0
This is a typical pattern for joining a key/value table where the (id/key) pairs are unique.
Edit Unfortunately it generates duplicate result set rows in situations where there's a duplicate key for a particular value. To deal with that, it's necessary to deduplicate the key/value table (processing) in this case.
This subquery will do that, taking the latest date value.
SELECT type, order_id, MAX(date) AS date
FROM processing
GROUP BY type, order_id
Then you have to use that subquery in the main query. This is where it would be good if MySQL had common table expressions. But it doesn't so things get kind of verbose.
SELECT o.id AS order_id, o.status,
p1.date AS date_request,
p2.date AS date_request2,
p3.date AS date_invoice
FROM orders o
LEFT JOIN (
SELECT type, order_id, MAX(date) AS date
FROM processing
GROUP BY type, order_id
) p1 ON o.id = p1.order_id AND p1.type='send_request'
LEFT JOIN (
SELECT type, order_id, MAX(date) AS date
FROM processing
GROUP BY type, order_id
) p2 ON o.id = p2.order_id AND p2.type='send_request2'
LEFT JOIN (
SELECT type, order_id, MAX(date) AS date
FROM processing
GROUP BY type, order_id
) p3 ON o.id = p3.order_id AND p3.type='send_invoice'
ORDER BY 1,2

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'