I have following table
+-----+--------+-----------+-----------+-------+
| id | job_id | source_id | target_id | value |
+-----+--------+-----------+-----------+-------+
| 204 | 5283 | 247 | 228 | 1201 |
| 349 | 4006 | 247 | 228 | 100 |
| 350 | 4007 | 247 | 228 | 500 |
| 351 | 4008 | 247 | 228 | 1000 |
| 352 | 4009 | 1 | 100 | 100 |
| 353 | 4010 | 1 | 100 | 500 |
| 354 | 4011 | 1 | 100 | 50 |
+-----+--------+-----------+-----------+-------+
I want to create a diff between the column value groupped by source_id and target_id. The older one (smaller id) should be compared with the newer one
I have searched a little bit and found coalesce. I have written a small query and it works in "general", but not as expexted:
SELECT
c.id, c.source_id, c.target_id, c.value, COALESCE(c1.value - c.value, -1) AS diff
FROM
changes c LEFT JOIN changes c1 ON (c1.source_id = c.source_id AND c1.target_id = c.target_id)
GROUP BY c.source_id, c.target_id, c.job_id
ORDER BY c.id
I got following result:
+-----+-----------+-----------+-------+------+
| id | source_id | target_id | value | diff |
+-----+-----------+-----------+-------+------+
| 204 | 247 | 228 | 1201 | 0 |
| 349 | 247 | 228 | 100 | 1101 |
| 350 | 247 | 228 | 500 | 701 |
| 351 | 247 | 228 | 1000 | 201 |
| 352 | 1 | 100 | 100 | 0 |
| 353 | 1 | 100 | 500 | -400 |
| 354 | 1 | 100 | 50 | 50 |
+-----+-----------+-----------+-------+------+
You can see the diff work for id 349 and 353, I want this for all rows like the following expected result:
+-----+-----------+-----------+-------+------+
| id | source_id | target_id | value | diff |
+-----+-----------+-----------+-------+------+
| 204 | 247 | 228 | 1201 | 1201 |
| 349 | 247 | 228 | 100 | 1101 |
| 350 | 247 | 228 | 500 | -400 |
| 351 | 247 | 228 | 1000 | -500 |
| 352 | 1 | 100 | 100 | 100 |
| 353 | 1 | 100 | 500 | -400 |
| 354 | 1 | 100 | 50 | 450 |
+-----+-----------+-----------+-------+------+
It would be no problem if the diff result is inverted.
What did I miss?
Thanks for any hints.
if you use user defined variables you don't need to join the table to itself. just do a row by row comparrision like so
SELECT
id,
job_id,
target_id,
if(#a = source_id, #b - value, value) as diff,
#b := value as value,
#a := source_id as source_id
FROM changes
CROSS JOIN (SELECT #a:=0, #b:=0)t
DEMO
I suspect that you're looking for something like this - although the COALESCE bit seems misleading to me...
SELECT a.*, COALESCE(b.value-a.value,a.value) diff
FROM
( SELECT x.* , COUNT(*) rank FROM changes x JOIN changes y ON y.id <= x.id GROUP BY x.id ) a
LEFT
JOIN
( SELECT x.* , COUNT(*) rank FROM changes x JOIN changes y ON y.id <= x.id GROUP BY x.id ) b
ON b.source_id = a.source_id
AND b.rank = a.rank - 1;
I think you want:
SELECT c.id,
c.source_id,
c.target_id,
c.value,
c.value - COALESCE(co.value, 0) delta
FROM changes c
LEFT JOIN (
SELECT ci.id, MAX(cio.id) prev_id
FROM changes ci
JOIN changes cio
ON cio.source_id = ci.source_id
AND cio.target_id = ci.target_id
AND cio.id < ci.id
GROUP BY ci.id
) link
ON link.id = c.id
LEFT JOIN changes co
ON co.id = link.prev_id
ORDER BY c.id
I have changed the logic slightly.
In your expected results, the first diff has gone from unknown (0?) to 1201 and is reported as a positive diff, but the second has gone from 1201 to 100 and is still reported as positive.
I have changed the name to delta, and given you the number required to move from the previous value to the new value. Obviously you can change this if you want to:
COALESCE(co.value-c.value, c.value) diff
which will get you the results you provided (with the diff 500 changed to -500, which I believe was a typo).
Related
I'm trying to figure out how I can run a query on the results of a join statement I'm doing between two tables. Basically, I need to get all the entries from More_Info that match the ID of Source_Table between a certain time, and then calculate the difference between Number where PartID = certain things.
Consider the following two tables:
Source_Table
UniqueID | TimeIn |
1 | 051010|
2 | 051545|
3 | 055412|
More_Info
UniqueID | PartID | Number |
1 | 500 | 5 |
1 | 505 | 10 |
1 | 510 | 40 |
2 | 500 | 10 |
2 | 505 | 15 |
2 | 510 | 25 |
4 | 500 | 30 |
6 | 505 | 10 |
So I know I can run select * from Source_Table left join More_Info using(UniqueID) which will return:
UniqueID | PartID | Number |
1 | 500 | 5 |
1 | 505 | 10 |
1 | 510 | 40 |
2 | 500 | 10 |
2 | 505 | 15 |
2 | 510 | 25 |
From this, what I need is to get 'Number' where PartID = 500 or 505, and get the difference, where the results would be like:
UniqueID | Difference |
1 | 5 |
2 | 5 |
Having a big of difficulty wrapping my head around this, so any help would be appreciated.
You could use a couple of subquery eg:
select t1.UniqueId, t2.NUmber - t1.Number from (
select * from Source_Table left join More_Info using(UniqueID)
) t1
INNER JOIN (
select * from Source_Table left join More_Info using(UniqueID)
) t2 on t1.UniqueID = t2.UniqueID and t1.PartID = 500 and t2.partId = 505
The goal is the get the price of the nearest number of the m3 and weight and put this in a table.
This sample works for me. But i hard code m3,weight,country and transportername
Query1:
SELECT
country,
transportername,
ABS(m3-0.5) as ABS_M3 ,
m3,
ABS(weight-5) as ABS_weight,
weight,
price
FROM database.transportcost
WHERE m3 >= 0.5 AND
weight >= 5 AND
country = "GB" AND
transportername like '%aa%'
Group by transportername
Order by ABS(m3-0.5) +
ABS(weight-5) +
price
Now i want to get the hard code value from a other table. I don't know what value i need to put in ~~xx.volumen~~ and ~~xx.gewicht~~.
Query2:
INSERT INTO database.transportcostPerItem (sku,country,transportname,weight,m3,price)
SELECT g.orderitemid, p2.country, p2.transportername, p2.weight, p2.m3, p2.price
FROM database.orderitem g
JOIN database.order i on i.orderid = g.orderid
JOIN database.matrixtable xx on g.orderitemid = xx.sku
JOIN database.vlog cc on i.orderid = cc.orderid
JOIN
(
SELECT *
FROM database.transportcost
Group by transportername
Order by ABS(m3-~~xx.volumen~~) +
ABS(weight-~~xx.gewicht~~) +
price
) as p2 on p2.country = i._country AND
p2.transportername = cc._transportername AND
p2.weight = xx.gewicht AND
p2.m3 = xx.volumen
;
Edit:
Sample data
Table: database.transportcost
country | transportername | m3 | weight | price
--------+-----------------+--------+--------+--------
GB | aa | 50.00 | 50 | 77.70
GB | bb | 0.50 | 125 | 83.19
GB | cc | 0.50 | 125 | 96.03
GB | bb | 0.60 | 150 | 83.19
GB | aa | 75.00 | 75 | 89.04
GB | cc | 0.60 | 150 | 96.03
GB | dd | 50.00 | 50 | 163.38
GB | cc | 0.70 | 175 | 96.03
GB | bb | 0.70 | 175 | 96.85
GB | ee | 0.53 | 175 | 102.78
GB | gg | 0.53 | 175 | 110.37
GB | aa | 100.00 | 100 | 89.04
GB | cc | 0.80 | 200 | 96.03
GB | bb | 0.80 | 200 | 96.85
GB | ff | 0.60 | 200 | 110.33
DE | aaa | 0.50 | 50 | 26.40
DE | bbb | 0.50 | 75 | 31.84
DE | aaa | 0.75 | 75 | 34.19
DE | ccc | 0.50 | 100 | 34.17
DE | bbb | 0.67 | 100 | 35.47
DE | ccc | 1.00 | 100 | 37.59
DE | ddd | 0.50 | 100 | 62.38
DE | ccc | 0.63 | 125 | 43.04
DE | bbb | 0.83 | 125 | 44.24
DE | aaa | 0.93 | 125 | 45.84
DE | eee | 0.50 | 125 | 53.80
DE | fff | 0.50 | 125 | 54.02
Query 1 results for the country GB
country | transportername | ABS_M3 | m3 | ABS_weight | weight | price
--------+-----------------+-----------------------+-------+------------+--------+-------
GB | aa | 49.5 | 50.00 | 45 | 50 | 77.70
GB | bb | 0 | 0.50 | 120 | 125 | 83.19
GB | cc | 0 | 0.50 | 120 | 125 | 96.03
GB | dd | 49.5 | 50.00 | 45 | 50 | 163.38
GB | ee | 0.030000000000000027 | 0.53 | 170 | 175 | 102.78
GB | gg | 0.030000000000000027 | 0.53 | 170 | 175 | 110.37
Query 1 results for the country DE
country | transportername | ABS_M3 | m3 | ABS_weight | weight | price
--------+-----------------+--------+------+------------+--------+-------
DE | aaa | 0 | 0.50 | 45 | 50 | 26.40
DE | bbb | 0 | 0.50 | 70 | 75 | 31.84
DE | ccc | 0 | 0.50 | 95 | 100 | 34.17
DE | ddd | 0 | 0.50 | 95 | 100 | 62.38
DE | eee | 0 | 0.50 | 120 | 125 | 53.80
DE | fff | 0 | 0.50 | 120 | 125 | 54.02
DE | ggg | 0 | 0.50 | 195 | 200 | 87.29
Results in the end Query 2 should look like this:
Table: database.transportcostPerItem
orderitemid | country | transportername | m3 | weight | price
------------+---------+-----------------+-----+--------+------
1 | GB | aa | 0,5 | 5 | 77.70
2 | DE | aaa | 0,5 | 5 | 26.40
It seems you are merely looking for the cheapest transport for given m3 and weight. In a first step you'd find all transports for at least the m3 and weight given. Of these you pick the lowest price then.
select *
from transportcost
where country = 'GB'
and m3 >= 0.5
and weight >= 5
order by price
limit 1;
If you wanted the measures closest to your given m3 and weight instead, even if that transport would be more expensive, you could order by the sum of the percentages:
select *
from transportcost
where country = 'GB'
and m3 >= 0.5
and weight >= 5
order by m3 / 0.5 + weight / 5, price
limit 1;
Now instead of given m3, weight, country, and transporter name, you get the values from an order details table. If this were just about a single order details record, the approach would be exactly the same, only instead of comparing with fixed values (m3 >= 0.5) you'd compare with the order details record's values (transportcost.m3 >= orderdetail.m3). Alas, with multiple order details records this approach doesn't work anymore, because we cannot limit the results to one row, but need one row per order details record instead. This would be solved with window functions (ROW_NUMBER, RANK etc.) or lateral joins (CROSS APPLY) in standard SQL. MySQL features neither.
Here is how to join the transport cost table:
select *
from <your order tables>
join transportcost tc
where tc.country = i._country
and tc._transportername = cc._transportername
and tc.m3 >= xx.volumen
and tc.weight >= xx.gewicht;
And now you must find a way to rank your results, so as to only get the best match per order detail. One way is to emulate ROW_NUMBER with variables. You may want to look this up in other answers. Another would be a limit subquery in the SELECT clause, but for this to work you need a single column identifying a record in the transport cost table. Let's say you add a column called ID and fill it with unique values...
select <some order columns>, tc.*
from
(
select <some order columns>,
(
select id
from transportcost tc
where tc.country = i._country
and tc._transportername = cc._transportername
and tc.m3 >= xx.volumen
and tc.weight >= xx.gewicht
order by tc.m3 / xx.volumen + tc.weight / xx.gewicht, tc.price
limit 1
) as best_transportcost_id
from <your order tables>
) data
join transportcost tc
where tc.id = data.best_transportcost_id;
(You could do this without an ID somehow by concatenating the values, e.g. 'GB-aa-50.00-50-77.70', so as to have a string identifying a transport cost record, but I don't recommend this. It's better to have a unique ID with an index for quick lookups. And even better would be to work with a better DBMS :-)
I used the solution of #Thorsten.
This is the results
INSERT INTO database.transportcostperitem (transportcostID, orderID, sku, country, transportername, weight, m3,price,shippingmethod,shippingstatus,shippingDate)
SELECT
transportcostID,
orderID,
sku,
_country,
transportername,
transportTmp._weightReal,
transportTmp._m3 ,
price,
_shippingMethod,
_shippingStatus,
_shippingDate
FROM(
SELECT
b.orderID,
o.sku,
b.transporter,
o._country,
i._shippingMethod,
i._shippingStatus,
i._shippingDate,
o._m3,
o._weightReal,
(
SELECT id
FROM database.transportcost tc
where
tc.transportername = b._transporterName AND
tc.country = o._country AND
tc.weight >= o._weightReal AND
tc.m3 >= o._m3
order by o._m3 / tc.m3 + o._weightReal / tc.weight , tc.price
limit 1
) as transportcostID
FROM database.orderitem o
JOIN database.order i on i.orderID = o.orderID
JOIN database.vlog b on b.orderID = o.orderID
WHERE sku >0
)as transportTmp
JOIN database.transportcost tc
where tc.id = transportcostID AND
_shippingMethod is not null
orderID by sku
;
i have following scheme,
purchase_order
+-------------------+----------------------+
| purchase_order_id | purchase_order |
+-------------------+----------------------+
| 54 | Purchase Order 12345 |
| 56 | po-laptop-hp-3 |
| 57 | po-laptop-hp-1 |
+-------------------+----------------------+
purchase_order_detail
+--------------------------+-------------------+---------+------------------+
| purchase_order_detail_id | purchase_order_id | item_id | ordered_quantity |
+--------------------------+-------------------+---------+------------------+
| 61 | 54 | 279 | 500 |
| 62 | 54 | 286 | 700 |
| 63 | 56 | 279 | 43 |
| 64 | 57 | 279 | 43 |
| 65 | 57 | 286 | 43 |
| 66 | 57 | 287 | 43 |
+--------------------------+-------------------+---------+------------------+
delivery_order
+-------------------+--------------------------+-------------------+
| delivery_order_id | purchase_order_detail_id | recieved_quantity |
+-------------------+--------------------------+-------------------+
| 62 | 61 | 250 |
| 63 | 62 | 300 |
| 64 | 63 | 34 |
| 65 | 64 | 34 |
| 66 | 65 | 34 |
| 67 | 66 | 34 |
| 68 | 61 | 34 |
| 69 | 61 | 34 |
+-------------------+--------------------------+-------------------+
stock
+----------+-------------------+------------+----------+------------------+---------------+
| stock_id | delivery_order_id | project_id | quantity | initial_quantity | stock_type_id |
+----------+-------------------+------------+----------+------------------+---------------+
| 12 | 62 | 1 | 60 | 60 | 1 |
| 13 | 63 | 1 | 120 | 120 | 1 |
| 14 | 63 | 1 | 50 | 50 | 1 |
| 15 | 64 | 1 | 12 | 12 | 1 |
| 16 | 62 | 1 | 120 | 120 | 1 |
| 17 | 62 | 1 | 12 | 12 | 1 |
+----------+-------------------+------------+----------+------------------+---------------+
i have write this query but it returns duplicate results
SELECT po.created_on
, po.purchase_order
, i.item_name
, u.unit_name
, pod.ordered_quantity
, do.recieved_quantity
, do.recieved_on
, po.remarks
FROM purchase_order po
, purchase_order_detail pod
, delivery_order do
, stock s
, item i
, unit u
WHERE u.unit_id = i.unit_id
AND i.item_id = pod.item_id
AND po.purchase_order_id = pod.purchase_order_id
AND pod.purchase_order_detail_id = do.purchase_order_detail_id
AND do.delivery_order_id = s.delivery_order_id
AND s.project_id = 1
ORDER BY po.purchase_order_id
, pod.item_id
;
The results
+---------------------+----------------------+------------+-----------+------------------+-------------------+---------------------+---------------------------------------+
| created_on | purchase_order | item_name | unit_name | ordered_quantity | recieved_quantity | recieved_on | remarks |
+---------------------+----------------------+------------+-----------+------------------+-------------------+---------------------+---------------------------------------+
| 2015-02-24 22:48:15 | Purchase Order 12345 | HP Laptops | Unit | 500 | 250 | 2015-02-21 00:00:00 | Adding first Purchase Order as a Test |
| 2015-02-24 22:48:15 | Purchase Order 12345 | HP Laptops | Unit | 500 | 250 | 2015-02-21 00:00:00 | Adding first Purchase Order as a Test |
| 2015-02-24 22:48:15 | Purchase Order 12345 | Lenovo | Unit | 700 | 300 | 2015-02-21 00:00:00 | Adding first Purchase Order as a Test |
| 2015-02-24 22:48:15 | Purchase Order 12345 | Lenovo | Unit | 700 | 300 | 2015-02-21 00:00:00 | Adding first Purchase Order as a Test |
| 2015-02-24 22:55:40 | po-laptop-hp-3 | HP Laptops | Unit | 43 | 34 | 2015-02-21 00:00:00 | dfgsdfgsd |
+---------------------+----------------------+------------+-----------+------------------+-------------------+---------------------+---------------------------------------+
relationship is one to many from top to bottom.
What I wanted to get is the each purchase_order , his ordered quantity of each item, and total recieved quantity, and quantity in stock where project_id = 1 from stock.
i am expecting something like this,
+-------------------+---------+------------------+---------------+----------+
| purchase_order_id | item_id | ordered_quantity | totalReceived | quantity |
+-------------------+---------+------------------+---------------+----------+
| 54 | 279 | 500 | 314 | 192 |
| 54 | 286 | 700 | 300 | 170 |
| 56 | 279 | 43 | 34 | 12 |
+-------------------+---------+------------------+---------------+----------+
EDIT
Thank you for clearing up the mistake in my first part. I realize now that we cannot do all calculations in a single query (because we group on different columns in various parts) so I started by writing individual subqueries and joining them together. The steps went something like this:
Get the sum of received total received quantity for each
purchase_order_detail_id from the delivery_order table.
Join that subquery with the delivery_order table itself to get the totalReceived for the various delivery_order_id values.
Join that result set with the purchase_order_detail table to get the purchase_order_id, item_id, and ordered_quantity for each delivery_order_id.
We now have a result set including the delivery_order_id, purchase_order_id, item_id, ordered_quantity, and total received. The last two things are:
Get the SUM() of quantity for each delivery_order_id from the stock table.
Join that with our above result set on the condition that order_id matches (so we will only get one row) and that project_id is 1 (so we only get the necessary delivery_order_id values). I put that condition in the WHERE clause of the sum subquery.
Here is your final query:
SELECT tmp1.purchase_order_id, tmp1.item_id, tmp1.ordered_quantity, tmp1.totalReceived, tmp2.quantity
FROM(
SELECT tmp.delivery_order_id, pod.purchase_order_id, pod.item_id, pod.ordered_quantity, tmp.totalReceived
FROM purchase_order_detail pod
JOIN(
SELECT do.delivery_order_id, tmp.purchase_order_detail_id, tmp.totalReceived
FROM delivery_order do
JOIN(
SELECT do.purchase_order_detail_id, SUM(do.received_quantity) AS totalReceived
FROM delivery_order do
GROUP BY do.purchase_order_detail_id) tmp ON tmp.purchase_order_detail_id = do.purchase_order_detail_id)
tmp ON tmp.purchase_order_detail_id = pod.purchase_order_detail_id) tmp1
JOIN(
SELECT s.delivery_order_id, SUM(quantity) AS quantity
FROM stock s
WHERE s.project_id = 1
GROUP BY s.delivery_order_id) tmp2 ON tmp2.delivery_order_id = tmp1.delivery_order_id;
Here is the SQL Fiddle. It shows all of the intermediate steps too, if you'd like to see how the results came together individually.
Try modifying your query to use DISTINCT and OUTER JOINs instead of cartesian ("comma") joins.
SELECT DISTINCT po.created_on
, po.purchase_order
, i.item_name
, u.unit_name
, pod.ordered_quantity
, do.recieved_quantity
, do.recieved_on
, po.remarks
FROM purchase_order po
LEFT JOIN purchase_order_detail pod USING (purchase_order_id)
LEFT JOIN delivery_order do USING (purchase_order_detail_id)
LEFT JOIN stock s USING (delivery_order_id)
LEFT JOIN item i USING (item_id)
LEFT JOIN unit u USING (unit_id)
ORDER BY po.purchase_order_id
, pod.item_id
;
I have the following table structure:
+------+-------+-------+--------+
| mid | a | b | points |
+------+-------+-------+--------+
| 69 | 3137 | 13316 | 210 |
| 70 | 13316 | 3137 | 350 |
| 71 | 3497 | 13316 | 200 |
| 72 | 13316 | 3497 | 25 |
| 73 | 3605 | 13316 | 205 |
| 74 | 13316 | 3605 | 290 |
+------+-------+-------+--------+
I want to add the "points" values of two rows when "a" of row 1 = "b" of row 2 and "a" of row 2 = "b" of row 1.
The output needs to be something like this:
+------+-------+-------+--------+
| mid | a | b | points |
+------+-------+-------+--------+
| 69 | 3137 | 13316 | 560 |
| 71 | 3497 | 13316 | 225 |
| 73 | 3605 | 13316 | 495 |
+------+-------+-------+--------+
You can try it this way
SELECT t1.mid, t1.a, t1.b, t1.points + t2.points points
FROM table1 t1 JOIN table1 t2
ON t1.a = t2.b
AND t1.b = t2.a
AND t1.mid < t2.mid
or leveraging MySQL non-standard GROUP BY extension
SELECT mid, a, b, SUM(points) points
FROM
(
SELECT mid, a, b, points
FROM table1
ORDER BY mid
) q
GROUP BY LEAST(a, b), GREATEST(a, b)
Output:
| MID | A | B | POINTS |
|-----|------|-------|--------|
| 69 | 3137 | 13316 | 560 |
| 71 | 3497 | 13316 | 225 |
| 73 | 3605 | 13316 | 495 |
Here is SQLFiddle demo
If I've understood correctly then you want:
SELECT p1.mid, p1.a, p1.b, p1.points + p2.points points
FROM points p1
INNER JOIN points p2 ON p1.a = p2.b AND p1.b = p2.a
WHERE p1.mid < p2.mid
I have knocked it up in sql fiddle and gives the output that you want.
I'm using PHP and I have the following two tables:
REVIEWS
| id | Item | editor_rating | user_votes |
------------------------------------------------
| 1 | item_1 | 18.1 | 415 |
| 2 | item_2 | 17.1 | 371 |
| 3 | item_3 | 14.7 | 111 |
| 8 | item_8 | 15.3 | 215 |
| 9 | item_9 | 17.7 | 119 |
| 10 | item_10 | 17.0 | 66 |
FILTERS
| id | Item | published |
----------------------------------
| 1 | item_1 | 1 |
| 2 | item_2 | 1 |
| 3 | item_3 | 1 |
| 8 | item_8 | 1 |
| 9 | item_9 | 1 |
| 10 | item_10 | 1 |
The following query works correctly and returns all the rows:
SELECT * FROM reviews AS r
JOIN filters AS f ON (r.id = f.id)
WHERE f.published = 1
So I'm on the right way.
Now I would like to do some math operations on the records. For example sum the fields editor_rating and user_votes and list the rows ordered by DESC. I tried the following but it returns uncorrect results (not MySQL error, a sum error):
SELECT *, r.editor_rating+r.user_votes AS total FROM reviews AS r
JOIN filters AS f ON (r.id = f.id)
WHERE f.published = 1 ORDER BY total DESC
The tables above contains the actual dB data. By summing editor_rating and user_votes I should have a list ordered as follows:
18.1 + 415 = 433.1 = Item_1
17.1 + 371 = 388.1 = Item_2
15.3 + 215 = 230.3 = Item_8
instead I get the following list:
Item_8
Item_9
Item_10
First check if these values is varchar then you have to cast it first :
SELECT *, cast(r.editor_rating as unsigned )+ cast(r.user_rating as unsigned ) AS total FROM reviews AS r JOIN filters AS f ON (r.id = f.id) WHERE f.published = 1 ORDER BY total DESC
It run for me when i cast it first to unsigned integer ..