This question already has answers here:
SQL NOT IN not working
(4 answers)
Closed 8 years ago.
I am using Mysql and trying to migrate data from one DB to other. I have not worked on databases earlier.
This query gives me close to 300 results
select distinct internal_id from ratingsapp.hotel03
But this one returns no results and has no errors either:
select restname from City.resturant where restid not in
(select distinct internal_id from ratingsapp.hotel03)
Now if I manually pick few internal_ids from the hotel03 table, and put this in place of the nested query, the query returns proper results. I am not sure what exactly am I doing wrong.
This usually happens when one of the values is NULL. So this might work:
select restname
from City.resturant
where restid not in (select distinct internal_id from ratingsapp.hotel03 where internal_id is not null);
Another way to write this query is with not exists:
select restname
from City.resturant r
where not exists (select 1
from ratingsapp.hotel03 h
where h.internal_id = r.restid
);
The way this works, NULL is handled correctly without directly checking for it. That is one reason why NOT EXISTS is preferable to NOT IN.
Are you sure it is not because all the restid from City.restaurant are in internal_id of ratingsapp.hotel03 ? You say that you manually pick a few of these ids and there was a result, but check this:
distinct City.restaurant.restid: 1, 2, 3, 4, 5
distinct ratingsapp.hotel03.internal_id: 1, 2, 3, 4, 5
Then your query will return nothing, as all the restid are not not in the internal_id. But if you pick a few ids from ratingsapp.hotel03.internal_id, for instance:
select restname
from City.resturant
where restid not in (1, 2, 3)
Then you will have all the City.restaurant with a restid of 4 or 5!
Related
I am trying to make a request where I select from an array of value using the IN, but inside this array, if I have the same value twice, I'd like the request to return the result twice.
To clarify, here is an example:
select id_exo, count(id_exo) FROM BLOC WHERE id_seance IN (10,10) group by id_exo
So inside the IN, I put 2 times the value 10.
Here is the result:
id_exo
count(id_exo)
60
1
82
1
But in count, I'd like to have the number 2 since I have put twice 10 inside my IN.
How can I achieve that?
SELECT id_exo, COUNT(id_exo)
FROM bloc
JOIN (SELECT 10 id_seance
UNION ALL
SELECT 10) val USING (id_seance)
GROUP BY id_exo
Prior to MySQL 8.0 you can join with a sub select:
select * from BLOC as b
inner join (
select 1 as 'id', 10 as 'value'
union
select 2,10
union
select 3,10) as myValues on myValues.value = b.id_seance
You need the id column as the UNION statement removes duplicate rows
If you are lucky enough to have MySQL 8.0 look at the VALUES statement
https://dev.mysql.com/doc/refman/8.0/en/values.html
Here you should instead be able to join with something like
VALUES ROW(10), ROW(10), ROW(10)
I'm trying to show staff_code, staff_name and dept_name for those who have taken one book.
Here's my query:
SELECT SM.STAFF_CODE,SM.STAFF_NAME,DM.DEPT_NAME,BT.BOOK_CODE
FROM STAFF_MASTER SM,DEPARTMENT_MASTER DM,BOOK_TRANSACTIONS BT
WHERE SM.DEPT_CODE =DM.DEPT_CODE
AND SM.STAFF_CODE = (
SELECT STAFF_CODE
FROM BOOK_TRANSACTIONS
HAVING COUNT(*) > 1
GROUP BY STAFF_CODE)
It gives the error:
single-row subquery returns more than one row.
How to solve this?
Change = to IN:
WHERE SM.STAFF_CODE IN (SELECT ...)
Because the select returns multiple values, using equals won't work, but IN returns true if any of the values in a list match. The list can be a hard-coded CSV list, or a select with one column like your query is.
That will fix the error, but you also need to remove BOOK_TRANSACTIONS from the table list and remove BOOK_CODE from the select list.
After making these changes, your query would look like this:
SELECT SM.STAFF_CODE,SM.STAFF_NAME,DM.DEPT_NAME
FROM STAFF_MASTER SM,DEPARTMENT_MASTER DM
WHERE SM.DEPT_CODE =DM.DEPT_CODE
AND SM.STAFF_CODE IN (
SELECT STAFF_CODE
FROM BOOK_TRANSACTIONS
HAVING COUNT(*) > 1
GROUP BY STAFF_CODE)
I recommend learning the modern (now over 25 year old) JOIN syntax.
I have the following SQL, which gives me the error that this union tabled called brokeredTable is not updateable.
UPDATE (SELECT chid,brokered,bid,uid,rate FROM spot_channels UNION SELECT tid,brokered,bid,uid,rate FROM tremor_tags) as brokeredTable SET brokered = 1, rate = 5, bid = 5, uid = 7 WHERE chid = 110399
As you can see the SQL is pretty simple, instead of running two update statements on two different tables I wanted to Union them into one set and then run the update against that set of data. Which apparently I cannot do this way.
Any Suggestions? Again I just want one SQL statement to accomplish this.
"The SQL UNION operator combines the result of two or more SELECT statements"
That query doesn't even have the UPDATE sintax. UPDATE table SET column = 'value'.
You should search before ask:
Performing an UPDATE with Union in SQL
Here is the story
i have two mysql tables like :
master
id, descr
1, master 1
2, master 2
details
id, descr, masterid
1, test 1, 1
2, test 2, 1
3, test 3, 1
4, test 1, 2
5, test 2, 2
6, test 3, 2
I need a query to get the rows from the first table and a looped column from the details
For example :
first execute :
1,master 1, 1
2,master 2, 4
second execute
1,master 1, 2<- From the details table
2,master 2, 5<- From the details table
third execute
1,master 1, 3<- From the details table
2,master 2, 6<- From the details table
Fourth execute :
1,master 1, 1
2,master 2, 4
I guess i have to add a column on master table to keep the last selected record from the details table but i can't design the query.
Any ideas?
Thank you
Vangelis
The thing is - you can do it with SQL only. But that will be session-related. By that, I mean this query:
SELECT
master.*,
o.id AS oid
FROM
master
INNER JOIN
(SELECT
d.*,
#num:=IF(#id=masterid, #num:=#num+1, 1) AS num,
#id:=masterid
FROM
(SELECT * FROM details ORDER BY masterid) AS d
CROSS JOIN
(SELECT #id:=0, #num:=0) AS init
) AS o
ON master.id=o.masterid
INNER JOIN
(SELECT
masterid,
COUNT(id) AS c
FROM
details
GROUP BY
masterid) AS counts
ON master.id=counts.masterid
CROSS JOIN
(SELECT #RUN_COUNT:=IF(#RUN_COUNT IS NULL, 1, #RUN_COUNT+1)) AS r
WHERE
o.num=IF(!(#RUN_COUNT%(counts.c)), counts.c, #RUN_COUNT%(counts.c));
Very important detail of it is #RUN_COUNT. It will be looped only in terms of one session. That is: if you'll start another session, then initializing of this variable will happen again:
(SELECT #RUN_COUNT:=IF(#RUN_COUNT IS NULL, 1, #RUN_COUNT+1)) AS r
-as you can see, this simply checks if it isn't initialized - and, if it's not, then it will initialize it. So, this will fail if you're acting in different sessions.
SQLFiddle behaves like one session, thus it's working there (but you'll need first to set #RUN_COUNT to NULL, of course - because I've already run this query)
The query above will work if there are different counts for different master ids (like I've done in fiddle, 4 for masterid=1 and 3 for masterid=2). But - again, you can not rely on #RUN_COUNT in common case. If your session isn't persistent between your application and your DBMS - then you'll have to handle it in application.
in reference to what I said earlier --- if you were to do it in php, this is the sql select you would want to do to get the data in the correct format.. from here you could do a loop inside a loop in php with a limit set to break at 2.. should probably do the trick
SELECT
m.id AS master_id,
m.descr,
d.id AS detail_id
FROM master m
JOIN details d ON d.masterid = m.id
i have simple query:
SELECT data FROM table WHERE id IN (5, 2, 8, 1, 10)
Question is, how can i select my data and order it like in my IN.
Order must be 5, 2, 8, 1, 10.
Problem is that i have no key for order. IN data is from other query (1), but i need to safe order.
Any solutions?
(1)
SELECT login
FROM posts
LEFT JOIN users ON posts.post_id=users.id
WHERE posts.post_n IN (
2280219,2372244, 2345146, 2374106, 2375952, 2375320, 2371611, 2360673, 2339976, 2331440, 2279494, 2329266, 2271919, 1672114, 2301856
)
Thanx for helping, solutions works but very slow, maybe find something better later, thanx anyway
The only way I can think to order by an arbitrary list would be to ORDER BY comparisons to each item in that list. It's ugly, but it will work. You may be better off sorting in whatever code you are doing the selection.
SELECT data FROM t1 WHERE id IN (5, 2, 8, 1, 10)
ORDER BY id = 10, id = 1, id = 8, id = 2, id = 5
The order is reversed because otherwise you would have to add DESC to each condition.
You can use a CASE statement
SELECT data
FROM table WHERE id IN (5, 2, 8, 1, 10)
ORDER BY CASE WHEN id = 5 THEN 1 WHEN id = 2 THEN 2 WHEN id = 8 THEN 3 WHEN id = 1 THEN 4 WHEN id = 10 THEN 5 END
SELECT data FROM table
WHERE id IN (5, 2, 8, 1, 10)
ORDER BY FIELD (id, 5, 2, 8, 1, 10)
http://dev.mysql.com/doc/refman/5.5/en/string-functions.html#function_field
Might be easier to auto-generate (because it basically just needs inserting the wanted IDs comma-separated in the same order a second time) than the other solutions suggested using CASE or a number of ID=x, ID=y ...
http://sqlfiddle.com/#!2/40b299/6
I think that's what you're looking for :D Adapt it to your own situation.
To do this dynamically, and within MySql, I would suggest to do the following:
Create a temp table or table variable (not sure if MySql has these), with two columns:
OrderID mediumint not null auto_increment
InValue mediumint -(or whatever type it is)
Insert the values of the IN clause in order, which will generate ID's in order of insertion
Add a JOIN to your query on this temp table
Change your Order By to be
order by TempTable.OrderID
Drop temp table (again, in SQL inside a stored proc, this is automatic, not sure about MySql so mentioning here for full disclosure)
This effectively circumvents the issue of you not having a key to order by in your table ... you create one. Should work.