Mysql having a table reference itself - mysql

What I'd like to do is for a gaming application I need to search for my non player characters and they have a field called target_id that stores the id of whatever they are chasing.
given:
table mobs with fields and some example data
id x y target_id
1 1 1 2
2 3 3 1
I would like to return the following data with a query
id x y target_id target_x target_y
1 1 1 2 3 3
2 3 3 1 1 1
This is what I tried but it has syntax errors
SELECT id,x,y,target_id, target.x, target.y FROM mobs LEFT JOIN mobs AS target ON target_id=id FROM mobs WHERE 1

I don't know why you have a WHERE 1 or the second FROM, but I believe that this is what you want:
SELECT M.id, M.x, M.y, M.target_id, T.x, T.y
FROM mobs AS M
LEFT JOIN mobs AS T
ON M.target_id = T.id
In the future, you should post your table definition, and the expected result so your question is more clear.

Correct syntax as far as I know is:
SELECT mobs.id, mobs.x, mobs.y, mobs.target_id, target.x, target.y
FROM mobs
LEFT JOIN mobs AS target
ON mobs.target_id = target.id
You've already specified the 'FROM' by saying 'JOIN' and you don't need a WHERE when you don't need to filter any rows
Edit: sorry I didn't put the aliases in - you need to make sure the last part (and the fields in the select) have which tables you want to target - remember, saying target_id doesn't mean much if you have two tables in the query with the same column name. You will get an ambiguity error otherwise. I've added the aliases to the query

Related

Different entries within 5 seconds

Sorry I don't know how to describe the topic.
i have a database where i store the unixtime of the entries and some other stuff, in this case the column "name" for the user and "type" it can be 1 or 2.
I want to check if there are entries where name is the same and type switches from 1 to 2 and back to 1 or 2 1 2 within 5 seconds.
So it shows me something like this:
Unixtime Name type
1550293559 Peter 2
1550293560 Peter 1
1550293561 Peter 2
Is there a query that can help me do this?
Sorry I really hope you guys understand that, I don't know how to explain the problem properly.
Thanks.
You can do that with a 3x self join on that table and the necessary conditions (All 3 rows have the same name etc.). See http://www.mysqltutorial.org/mysql-self-join/ for more info.
Note that as the join produces all the possible permutations as input material, you don't have to 'permute' the conditions in the where part of the query. E.g. To get the 5 second rule, you can just say
... where e1.unixtime > e2.unixtime and e2.unixtime > e3.unixtime and e3.unixtime+6 > e1.unixtime ...
Edit: since the original answer was downwoted, here is the full query (grumble grumble) assuming the table name 'sotest':
SELECT
*
FROM
sotest e1
JOIN
sotest e2
JOIN
sotest e3
WHERE
(e1.name = e2.name AND e2.name = e3.name
AND e1.unixtime > e2.unixtime
AND e2.unixtime > e3.unixtime
AND e3.unixtime + 6 > e1.unixtime)
AND ((e1.type = 1 AND e2.type = 2
AND e3.type = 1)
OR (e1.type = 2 AND e2.type = 1
AND e3.type = 2))

SQL unwanted results in NOT query

This looks like it should be really easy question, but I've been looking for an answer for the past two days and can't find it. Please help!
I have two tables along the lines of
texts.text_id, texts.other_stuff...
pairs.pair_id, pairs.textA, pairs.textB
The second table defines pairs of entries from the first table.
What I need is the reverse of an ordinary LEFT JOIN query like:
SELECT texts.text_id
FROM texts
LEFT JOIN text_pairs
ON texts.text_id = text_pairs.textA
WHERE text_pairs.textB = 123
ORDER BY texts.text_id
How do I get exclusively the texts that are not paired with A given textB? I've tried
WHERE text_pairs.textB != 123 OR WHERE text_pairs.textB IS NULL
However, this returns all the pairs where textB is not 123. So, in a situation like
textA TextB
1 3
1 4
2 4
if I ask for textB != 3, the query returns 1 and 2. I need something that will just give me 1.
The comparison on the second table goes in the ON clause. Then you add a condition to see if there is no match:
SELECT t.text_id
FROM texts t LEFT JOIN
text_pairs tp
ON t.text_id = tp.textA AND tp.textB = 123
WHERE tp.textB IS NULL
ORDER BY t.text_id ;
This logic is often expressed using NOT EXISTS or NOT IN:
select t.*
from texts t
where not exists (select 1
from text_pairs tp
where t.text_id = tp.textA AND tp.textB = 123
);

MySQL Query with LEFT JOIN where second table has a 2-Part Primary Key

I have 2 tables in a MySQL database (storeskus). The first is FBM_Orders and the second is IM_INV.
I am trying the query
SELECT `FBM_Orders`.`order-id`,`FBM_Orders`.`order-item-id`,`FBM_Orders`.`purchase-date`,
`FBM_Orders`.`promise-date`,`FBM_Orders`.`buyer-name`,`FBM_Orders`.`sku`,
`FBM_Orders`.`product-name`,`FBM_Orders`.`quantity-purchased`,
`FBM_Orders`.`recipient-name`,`IM_INV`.`LOC_ID`,`IM_INV`.`QTY_ON_HND`
FROM `FBM_Orders`
LEFT JOIN `IM_INV` ON `FBM_Orders`.`sku` = `IM_INV`.`ITEM_NO`
WHERE `FBM_Orders`.`quantity-to-ship` > 0
ORDER BY `FBM_Orders`.`purchase-date`, `IM_INV`.`LOC_ID` ASC;
Because the IM_INV table has a 2-part primary key: ITEM_NO & LOC_ID, I am getting 4 lines for each ITEM_NO with the QTY_ON_HND for each of the 4 locations (LOC_ID).
I am fairly new to SQL so I'm thrilled to have gotten this far, but how can I make it so that the result is a single line per ITEM_NO but with a column for each LOC_ID with its QTY_ON_HND?
Example:
My current result is
FBM_Order.sku FBM_Order.quantity-purchased IM_INV.LOC_ID QTY_ON_HND
'SCHO645256' 1 AF 2
'SCHO645256' 1 LO 2
'SCHO645256' 1 S 3
'SCHO645256' 1 SL 1
How can I change that to
FBM_Order.sku FBM_Order.quantity-purchased QTY_ON_HND_AF QTY_ON_HND_LO QTY_ON_HND_S QTY_ON_HND_SL
'SCHO645256' 1 2 2 3 1
?
Thanks!
You may load it as you already do and treat it inside your application, but if you really wanna make that inside your MySQL, try GROUP CONCAT and JSON as follows:
SELECT
GROUP_CONCAT(JSON_OBJECT(
'LOC_ID', IM_INV.LOC_ID,
'QTY_ON_HND', QTY_ON_HND
))
{another fields}
FROM `FBM_Orders`
LEFT JOIN `IM_INV` ON `FBM_Orders`.`sku` = `IM_INV`.`ITEM_NO`
WHERE `FBM_Orders`.`quantity-to-ship` > 0
GROUP BY `FBM_Orders`.`order-id`;
Note: JSON is just available for MySQL 5.7+ and may slow down your query a little bit. You're still gonna need convert your data to array inside your application. So it's half done inside your app and half inside your database.

Combine database queries

I have a MySQL table that looks like this:
ID / x_id / x_key / x_value
322 / 4 / name / Jack
323 / 5 / name / Mary
324 / 6 / name / John
325 / 4 / hide / 1
326 / 5 / hide / 0
327 / 6 / hide / 0
I would like to select the names from the persons which "hide" key corresponds to the "0" value.
Here these selected "x_values" would then be Mary and John
To do so, I have the x_id that I can compare between records.
Which x_id's correspond to an x_ key="hide" that matches an x_value = "0"?
Both x_id's 5 and 6.
Which "x_values" are corresponding to these two x_id's where the x_key="name"? Mary and John
In other words, I try to get a single query that would mix these two queries in order to get Mary and John only:
Query A:
SELECT
x_id,
x_value
FROM
mytable
WHERE
x_key='name'
Query B:
SELECT
x_id
FROM
mytable
WHERE
x_key='hide'
AND
x_value='0'
I just don't find the correct way to do that.
How can I?
I'm really sorry for the explanation but I'm not english and it is very hard to explain.
If i have understood you correct you want to select the elements that have a specific x_key with x_value = '0' and that are not hidden (x_key != 'hide').
EDIT (according to your edit):
SQL Fiddle
SELECT bb.x_value
FROM mytable AS aa
INNER JOIN mytable AS bb
ON aa.x_id = bb.x_id
WHERE aa.x_key = 'hide' AND aa.x_value = 0 AND bb.x_key = 'name';
OLD ANSWER (before your edit):
SELECT x_id, x_key, x_value
FROM mytable
WHERE x_key='name' AND x_key != 'hide' AND x_value = '0'
You should use join to connect two instances of the table - one for the names and one for the 'hides'
select n.x_id, n.x_value from mytable as h inner join myable as n on
h.x_id = n.x_id where n.x_key = 'name' and h.x_key = 'hide' and H.x_value = 0;
while this will work, I think it's not a good practice to have two types of data in the same table. I'd recommend you to split it to two tables- one for names and one for hides
If I understand you correct you want combine 2 'SELECT' with different 'WHERE' statments. You can use 'OR' statment
SELECT x_id,x_value FROM mytable WHERE x_key='name' OR x_key='hide' AND x_value='0'

mysql left join - returning rows using NULL and a condition

I have two tables: 'shift' and 'event'. One shift has many events.
Some sample data:
---- shift ----
id - location
1 - mcdonalds
2 - burger king
3 - subway
--- event ---
id - shift_id - type - note
1 - 1 - 2 - bingo
2 - 1 - 3 - bingo
3 - 2 - 4 - ignore
4 - 2 - 2 - ignore
An event has a type, so for example: type '4' represents an event starting a shift.
I want to build a query that returns all shifts that DO NOT have an event record where type = 4. So in the example above, I would bring back mcdonalds.
I've got as far as:
SELECT
shift.location AS location,
FROM shift
LEFT JOIN event ON event.shift_id=shift.id
and that's where I get stuck. Obviously one can add
WHERE event.type IS NULL
..but how does one only return rows where the null is for type = 4 ?
Thanks....!
The following query selects all the shifts that have type=4 in the event table. Then a LEFT JOIN is made between this data and the shift table. Rows having event.shift_id are selected (meaning that shift_id's that do not have type = 4).
SELECT
shift.*
FROM shift
LEFT JOIN (SELECT DISTINCT shift_id FROM event WHERE type = 4) event ON event.shift_id=shift.id
WHERE event.shift_id IS NULL;
SQL Fiddle demo
If you use LEFT JOIN you can discard the rows with type = 4 but if you have a shift with two events, one equals to 4 and another not equals... You'll get that shift because exists a row different by 4. When you use NOT EXISTS you do an analysys about all rows of your subquery.
Try this:
SELECT *
FROM shift s
WHERE NOT EXISTS(
SELECT 'EVENT'
FROM event e
WHERE e.shift_id = s.id
AND e.type = '4'
)