Since this is my first question here,
pls be gentle :)
In case the following qustion has already been dealt with,
I would be happy to get some links that answer my qustion.
I have a database which contains a log of items beeing moved around in a warehouse.
example:
tablename: inventory_history
Id , Uid , location
1 | a1 | location1
2 | a2 | location2
3 | a3 | location3
4 | a3 | location5
5 | a2 | badlocation
I want to select Id, Uid and location but only if the location of the fromer entry of the same Uid(but lower Id) is not eqaul to 'badlocation'.
So I want to check if the entry of the same Uid with the next lower Id hat 'badlocation' as value for location.
My first thought was to manage this with subquerys but on second thought i think it would be much faster and more clean if one could do this with a join.
I tried something like this:
SELECT a.id, a.uid, a.location from
wms_inventory_history as a
Inner Join wms_inventory_history as b ON (a.uid = b.uid)
Where a.id > b.id limit 1,1 AND
a.location != 'bad_location'
Related
I have a table containing items, each item belongs to an store, e.g:
id | name | store_id | price
1 | hat | 1 | 110
2 | bag | 1 | 120
3 | coat | 2 | 130
A Store can be canonical or a duplicate. A canonical Store has canonical_id equal to null, and a duplicate Store has canonical_id equal to the ID of the canonical Store, e.g:
id | name | canonical_id
1 | NYC | null
2 | Bronx | 1
I need to group items by their Store to get the total stock value of all items at the store, e.g:
SELECT store_id, SUM(price) as `stock_value` FROM items GROUP BY store_id
This would produce 2 results, Store 1 has a stock_value of 230 and Store 2 has a stock_value of 130.
Because Store 2 is a duplicate of Store 1 the items from Store 2 should be included in the total for Store 1. The goal is for this example to provide a single result of 360.
I think the correct implementation would involve some sort of join which retrieves the Store ID from stores by using IFNULL to get either the canonical_id or id after selecting based on id from the items table, but I'm struggling to implement a solution that works.
Any pointers would be greatly appreciated, thank you.
Edit: my attempt is as follows, it appears to meet my needs, are there any caveats / issues with my approach?
SELECT SUM(price) as `stock_value`, IFNULL(stores.canonical_id, store_id) as `store`
FROM items
JOIN stores on stores.id = items.store_id
GROUP BY store
I just realize you don't wanted to keep the stock_values of the "children" or "related" stores. However the next approach take those into account too:
SELECT
s.*,
(SELECT
SUM(i.price)
FROM
items AS i
INNER JOIN
stores AS s1 ON s1.id = i.store_id
WHERE
s1.cannonical_id = s.id
OR
s.id = i.store_id) AS "stock_value"
FROM
stores AS s
Online example: DB-Fiddle
If you don't want they, you just could filter the previous query using the condition WHERE s.cannonical_id is NULL like this:
SELECT
s.*,
(SELECT
SUM(i.price)
FROM
items AS i
INNER JOIN
stores AS s1 ON s1.id = i.store_id
WHERE
s1.cannonical_id = s.id
OR
s.id = i.store_id) AS "stock_value"
FROM
stores AS s
WHERE
s.cannonical_id is NULL
But, you should note that the query you posted on the updated question will be better in performance than this approach.
I have two tables, one is an index (or map) which helps when other when pulling queries.
SELECT v.*
FROM smv_ v
WHERE (SELECT p.network
FROM providers p
WHERE p.provider_id = v.provider_id) = 'RUU='
AND (SELECT p.va
FROM providers p
WHERE p.provider_id = v.provider_id) = 'MjU='
LIMIT 1;
Because we do not know the name of the column that holds the main data, we need to look it up, using the provider_id which is in both tables, and then query.
I am not getting any errors, but also no data back. I have spent the past hour trying to put this on sqlfiddle, but it kept crashing, so I just wanted to check if my code is really wrong, hence the crashing?
In the above example, I am looking in the providers table for column network, where the provider_id matches, and then use that as the column on smv.
I am sure i have done this before just like this, but after the weekend trying I thought i would ask on here.
Thanks in Advance.
UPDATE
Here is an example of the data:
THis is the providers, this links so no matter what the name of the column on the smv table, we can link them.
+---+---+---------------+---------+-------+--------+-----+-------+--------+
| | A | B | C | D | E | F | G | H |
+---+---+---------------+---------+-------+--------+-----+-------+--------+
| 1 | 1 | Home | network | batch | bs | bp | va | bex |
| 2 | 2 | Recharge | code | id | serial | pin | value | expire |
+---+---+---------------+---------+-------+--------+-----+-------+--------+
In the example above, G will mean in the smv column for recharge we be value. So that is what we would look for in our WHERE clause.
Here is the smv table:
+---+---+-----------+-----------+---+----+---------------------+-----+--+
| | A | B | C | D | E | F | value | va |
+---+---+-----------+-----------+---+----+---------------------+-----+--+
| 1 | 1 | X2 | Home | 4 | 10 | 2016-09-26 15:20:58 | | 7 |
| 2 | 2 | X2 | Recharge | 4 | 11 | 2016-09-26 15:20:58 | 9 | |
+---+---+-----------+-----------+---+----+---------------------+-----+--+
value in the same example as above would be 9, or 'RUU=' decoded.
So we do not know the name of the rows, until the row from smv is called, once we have this, we can look up what column name we need to get the correct information.
Hope this helps.
MORE INFO
At the point of triggering, we do not know what the row consists of the right data because some many of the fields would be empty. The map is there to help we query the right column, to get the right row (smv grows over time depending on whats uploaded.)
1) SELECT p.va FROM providers p WHERE p.network = 'Recharge' ;
2) SELECT s.* FROM smv s, providers p WHERE p.network = 'Recharge';
1) gives me the correct column I need to look up and query smv, using the above examples it would come back with "value". So I need to now look up, within the smv table, C = Recharge, and value = '9'. This should bring me back row 2 of the smv table.
So individually both 1 and 2 queries work, but I need them put together so the query is done on the database server.
Hope this gives more insight
Even More Info
From reading other posts, which are not really doing what I need, i have come up with this:
SELECT s.*
FROM (SELECT
(SELECT p.va
FROM dh_smv_providers p
WHERE p.provider_name = 'vodaphone'
LIMIT 1) AS net,
(SELECT p.bex
FROM dh_smv_providers p
WHERE p.provider_name = 'vodaphone'
LIMIT 1) AS bex
FROM dh_smv_providers) AS val, dh_smv_ s
WHERE s.provider_id = 'vodaphone' AND net = '20'
ORDER BY from_base64(val.bex) DESC;
The above comes back blank, but if i replace net, in the WHERE clause with a column I know exists, I do get the results expected:
SELECT s.*
FROM (SELECT
(SELECT p.va
FROM dh_smv_providers p
WHERE p.provider_name = 'vodaphone'
LIMIT 1) AS net,
(SELECT p.bex
FROM dh_smv_providers p
WHERE p.provider_name = 'vodaphone'
LIMIT 1) AS bex
FROM dh_smv_providers) AS val, dh_smv_ s
WHERE s.provider_id = 'vodaphone' AND value = '20'
ORDER BY from_base64(val.bex) DESC;
So what I am doing wrong, which is net, not showing the value derived from the subquery "value" ?
Thanks
SELECT
v.*,
p.network, p.va
FROM
smv_ v
INNER JOIN
providers p ON p.provider_id = v.provider_id
WHERE
p.network = 'RUU=' AND p.va = 'MjU='
LIMIT 1;
The tables talk to each other via the JOIN syntax. This completely circumvents the need (and limitations) of sub-selects.
The INNER JOIN means that only fully successful matches are returned, you may need to adjust this type of join for your situation but the SQL will return a row of all v columns where p.va = MjU and p.network = RUU and p.provider_id = v.provider_id.
What I was trying to explain in comments is that subqueries do not have any knowledge of their outer query:
SELECT *
FROM a
WHERE (SELECT * FROM b WHERE a)
AND (SELECT * FROM c WHERE a OR b)
This layout (as you have in your question) is that b knows nothing about a because the b query is executed first, then the c query, then finally the a query. So your original query is looking for WHERE p.provider_id = v.provider_id but v has not yet been defined so the result is false.
OK i found myself in a dead end, and i know must be a way but my brain is just about to explode. This is the case: I have two tables with tons of rows, one for works done (lets call it works table), something like this:
ID | Home_Work_ID | task_id | Person_id
1 | 23 | 1 | 30
2 | 23 | 2 | 31
3 | 23 | 3 | 30
4 | 876 | 1 | 31
5 | 123 | 3 | 32
and another table to report the fixes to do on the works mentioned before, lets call it fixes table
ID | Home_Work_ID | Person_reporting_id | Task_id | Details
1 | 23 | 93 | 1 | Fix this
2 | 23 | 85 | 3 | Fix that
3 | 123 | 86 | 3 | Fix something
As we can see, in the fixes table there are home works with fixes reported, and those home works was done by the person_id 30 and 32 (from the work table). The results that im trying to achieve would be:
Person | Fixes
John (lets say this is person id 30) | 2
Kate (lets say this is person id 32) | 1
The problem is, i need to create a report that show me who was the person responsable of the work done in the works table that have reported fixes in the second table and how many fixes was reported for that person. The only link is the home work id and probably the task id, so i was testing something like this
SELECT P.person_name AS Person, COUNT(F.id) AS fixes
FROM fixes F
INNER JOIN homeworks H ON F.home_work_id = H.id
INNER JOIN works as W
INNER JOIN people AS P ON W.person_id = P.id
INNER JOIN tasks AS T ON T.task_id = F.task_id
WHERE F.task_id = W.task_id
AND F.home_work_id = W.home_work_id
AND W.home_work_id IN (SELECT home_work_id FROM fixes GROUP BY home_work_id)
GROUP BY P.person_name ORDER BY fixes DESC
Ok there are three more inner/left joinable tables with the id and name of the person, home work and task. This show me the person responsable but the number of fixes for that person and that home_work/task dont match the ones in the fixes table, i guess im doing wrong inner joining the work table that way but i dont see the light yet. Any help will be really appreciated.
Regards
I think this query should give you the expected result:
SELECT P.Person_name AS Person, COUNT(F.id) AS fixes
FROM works W
INNER JOIN fixes F ON W.home_work_id = F.home_work_id and W.task_id=F.Task_id
INNER JOIN people P ON W.person_id = P.id
group by P.Person_name
however because I didn't read the question deeply, so I'm not sure
100% this will give exact result.
EDIT: question owner wrote the exact query of answer below.
Note from owner of the answer: Check the query, its based on it but not the "exact" query.
Ok after do some tests and thanks to the comments from Farhang Amary and Rick James from dba.stackexchange, the following query seems to do the job, so im posting it here for anyone that find itself on the same situation or for anything tha can be fixed on it:
SELECT P.Person_name AS Person, COUNT(F.id) AS fixes
FROM (SELECT person_id, home_work_id, task_id FROM work) W
LEFT JOIN fixes_table F ON W.home_work_id = F.home_work_id AND W.task_id = F.taks_id
LEFT JOIN People_table P ON W.person_id = P.id
GROUP BY P.person_name ORDER BY fixes DESC;
I'm having 2 tables. Table A contains a list of people who booked for an event, table B has a list of people the booker from table A brings with him/her. Both tables have many colums with unique data that I need to do certain calculations on in PHP , and as of now I do so by doing queries on the tables with a recursive PHP function to resolve it. I want to simplify the PHP and reduce the amount of queries that come from this recursive function by doing better MYSQL queries but I'm kind of stuck.
Because the table has way to many columns I will give an Excerpt of table A instead:
booking_id | A_customer | A_insurance
1 | 134 | 4
Excerpt of table B:
id | booking_id | B_insurance
1 | 1 | 0
2 | 1 | 1
3 | 1 | 1
4 | 1 | 3
The booking_id in table A is unique and set to auto increment, the booking_id in table b can occur many times (depending on how many guests the client from table A brings with him). Lets say I want to know every selected insurance from customer 134 and his guests, then I want the output like this:
booking_id | insurance
1 | 4
1 | 0
1 | 1
1 | 1
1 | 3
I have tried a couple of joins and this is the closest I've came yet, unfortunately this fails to show the row from A and only shows the matching rows in B.
SELECT a.booking_id,a.A_customer,a.A_insurance,b.booking_id,b.insurance FROM b INNER JOIN a ON (b.booking_id = a.booking_id) WHERE a.booking_id = 134
Can someone point me into the right direction ?
Please note: I have altered the table and column names for stackoverflow so it's easy for you guys to read, so it's possible that there is a typo that would break the query in it right now.
I think you need a union all for this:
select a.booking_id, a.insurance
from a
where a.a_customer = 134
union all
select b.booking_id, b.insurance
from a join
b
on a.booking_id = b.booking_id
where a.a_customer = 134;
The simplest way I can think of to achieve this is to use a UNION:
SELECT booking_id, A_insurance insurance
FROM A
WHERE booking_id = 134
UNION
SELECT booking_id, B_insurance insurance
FROM B
WHERE booking_id = 134
As my understanging of your isso is right, that should give you the result you need:
SELECT a.booking_id,a.insurance FROM a WHERE a.booking_id = 134
union
SELECT a.booking_id,b.insurance FROM b INNER JOIN a ON (b.booking_id = a.booking_id) WHERE a.booking_id = 134
I currently have this sql statement that I wrote and it works but it's not quite what I want. I've been working on it for hours but can't seem to get any further.
select parent.id as parent_id, parent.subject as parent,s.id,s.subject from (select s.id, s.subject from subjects s where parent_id = 0) parent join subjects s on parent.id = s.parent_id order by parent.subject, s.subject
It's grabbing all the subjects and ordering correctly but I also want to return the parent subject (parent_id = 0) at the top of each grouping. This is because some parents may not have subjects underneath but I still need to return them. Also the ordering is off when I try to do it as I want the parent first then it's child subjects. Hope that makes sense but if not just ask.
Any help would be appreciated.
Thanks
Steve
You're talking about grouping sets of rows by their parent rows.
The only way I know how to do this in MySQL is using the GROUP_CONCAT() function which won't group the subjects by row, but rather create a grouped string.
Here's what you can do:
SELECT
a.id,
a.subject,
GROUP_CONCAT(CONCAT(b.id, ':::', b.subject) ORDER BY b.subject SEPARATOR '|||') AS subjectlist
FROM
subjects a
LEFT JOIN
subjects b ON a.id = b.parent_id
WHERE
a.parent_id = 0
GROUP BY
a.id,
a.subject
ORDER BY
a.subject
So this will give you a result set like:
id | subject | subjectlist
---------------------------------------------------------------------
2 | subj1 | 23:::childsubj1|||28:::childsubj4
3 | subj2 | 18:::childsubj8|||55:::childsubj16
4 | subj3 | NULL
Depending on what language you are using in your application, you may be able to "explode" the subjects string into arrays delimited first by ||| which separates each subject, then ::: which separates that subject's ID and name.
Obviously, the downside of this is you have to make sure that your child subject name does not contain either ||| or ::: or whichever delimiters you decide to use.
Edit: Experimentally, I came up with this alternative solution which may be closer to what you're looking for:
Try:
SELECT
c.subj,
c.id
FROM
(
SELECT
CONCAT('---> ', b.subject) AS subj,
b.id,
CONCAT(a.subject, b.subject) AS orderfactor
FROM
subjects a
INNER JOIN
subjects b ON a.id = b.parent_id
WHERE
a.parent_id = 0
UNION ALL
SELECT
subject AS subj,
id,
subject AS orderfactor
FROM
subjects
WHERE
parent_id = 0
) c
ORDER BY
c.orderfactor
This query should give you a result along the lines of:
subject | id |
----------------------------------------------------------
subj1 | 2 |
---> childsubj1 | 23 |
---> childsubj4 | 28 |
subj2 | 3 |
---> childsubj8 | 18 |
---> childsubj16 | 55 |
subj3 | 4 |
subj4 | 5 |
---> childsubj10 | 79 |