I have a PHP coma separated string of ids like 1,2,3. I have a MySQL table which has id column
Table task_comments:
id
--
1
2
I want to get all the ids in the list which are not in the table. Here i would like to get the 3 as result.
Currently I am building a query like the following in PHP and it is working.
SELECT id FROM (
SELECT 1 id FROM DUAL
UNION ALL
SELECT 2 id FROM DUAL
UNION ALL
SELECT 3 id FROM DUAL
) a WHERE id NOT IN (SELECT id FROM task_comments);
I don't think this is a good way to do this. I want to know if there is a better method to do this, because if the list is big the union list will grow.
Thanks
PS: I can post the PHP code used to make the query also if needed.
PPS: I would like to know if there is better MySQL Query.
Your string separated values in PHP:
$my_ids = "1,2,3";
SQL query in PHP:
$query = "SELECT id FROM task_comments WHERE id IN ($my_ids)";
This will return the id values from database which is 1 or 2 or 3.
Then you can simply compare it.
What you do is already the way to do it. There is no other way to create sets to reason over than the (pretty ugly) union construct. You can leave of the "from dual"s and replace the union alls with plain unions to make it shorter - although with a very large list union all might be the more performant solution as it does not sort for duplicate deletion.
SELECT id FROM (
SELECT 1 id
UNION
SELECT 2 id
UNION
SELECT 3 id
) a WHERE id NOT IN (SELECT id FROM tasklist);
You might also want to have a look at temporary tables. That way you could create the set you need in a more natural way without hitting the limits of the large SQL involving unions.
CREATE TEMPORARY TABLE temp_table (id int);
INSERT INTO temp_table VALUES((1),(2),(3)); -- or just repeat for as many values as you might have from your app (batch insert?)
SELECT id FROM temp_table
WHERE id NOT IN (SELECT id FROM tasklist);
See more on temporary tables here.
You can do it like that: select your ids:
SELECT id FROM task_comments WHERE id IN (1,2,3)
(here (1,2,3) is built from your array data - for example, via implode() function)
Then, in a cycle, fetch your ids into an array and then use array_diff() to find absent values.
May be you should first save all the distinct id's from the table that are present in your string of id's -
SELECT DISTINCT id FROM task_comments WHERE id IN (1,2,3..)
and then compare the two.
Related
I am having two table
Table 1 having a field
id
book_ids
1
1,2,3
Table 2 have all the book Ids
select *
from table 2
where book_id in (select book_ids from table 1 where id=1) ;
this statement not returning all the book ids from table 2 having id 1,2,3
Can anyone help
You could use the FIND_IN_SET() function:
select *
from table 2
where FIND_IN_SET(book_id, (select book_ids from table 1 where id=1)) > 0;
Read the documentation I linked to for details on how that function works.
But only do this if your table remains small. Using this function spoils any opportunity to optimize the query with an index, so the larger your table gets, the performance will grow worse and worse.
Also FIND_IN_SET() doesn't work the way you expect if there are spaces in your comma-separated list.
try to store table1 values in rows of table not in a same field.
and then your SELECT IN works.
we are trying to build an application using PHP and MYSQL here we have more then 5 different category wise table like tblcategory1, tblcategory2, tblcategory3 and so on.
And each of the category table have a common userID field in all the tables.
We want to check in all the tables what are the entries we have with that particular userID.
Is there any query to checking from multiple tables?
Thank you (in advance)
Yes you need to look at the UNION keyword. It roughly works like this:
SELECT columnName
FROM category1
WHERE userID = 1
UNION
SELECT columnName
FROM category2
WHERE userID = 1
UNION
SELECT columnName
FROM category2
WHERE userID = 1
This is essentially 3 separate queries which all run as one, and the results are all joined together to form one list of results.
For more info: UNION
An alternative structure to #LaurenceFrost answer is to use UNION ALL to bring the tables together, then filter that result.
SELECT
columnName
FROM
(
SELECT userID, columnName FROM tblcategory1
UNION ALL
SELECT userID, columnName FROM tblcategory2
UNION ALL
SELECT userID, columnName FROM tblcategory3
UNION ALL
SELECT userID, columnName FROM tblcategory4
UNION ALL
SELECT userID, columnName FROM tblcategory5
)
ilvCategoryAll
WHERE
userID = 1
This layout becomes much more friendly when you have JOINs and other business logic, which you don't really want to have to repeat for every source table.
Also, it should be noted that I used UNION ALL rather than UNION. This is because UNION expressly removes duplicates, which can be an expensive process (even if there are no duplicates to find). UNION ALL, however, does not do this de-duplication and is significantly lower cost.
Note: the ilv in ilvCategoryAll means "in-line-view".
This may sound like an odd question, but I'm curious to know if it's possible...
Is there a way to simulate MySQL records using inline data? For instance, if it is possible, I would expect it to work something like this:
SELECT inlinedata.*
FROM (
('Emily' AS name, 26 AS age),
('Paul' AS name, 56 AS age)
) AS inlinedata
ORDER BY age
Unfortunately MySQL does not support the standard values row-constructor for this kind of things, so you need to use a "dummy" select for each row and combine the rows using UNION ALL
SELECT *
FROM (
select 'Emily' AS name, 26 AS age
union all
select 'Paul', 56
) AS inlinedata
ORDER BY age
The UNION ALL serves two purposes
It preserves any duplicate you might have on purpose
It's a (tiny) bit faster than a plain UNION (because it does not check for duplicates)
No, not without making it complicated, but you can create a temporary table and query that instead. Temporary tables are deleted when the current client session terminates.
You can query them and insert data into them just like with other tables. When you create them, you have to use the TEMPORARY keyword, like so:
CREATE TEMPORARY TABLE ...
This way, you can also reuse the data for multiple queries if needed, no data gets stored, and all records that you query have the right structure (whereas the syntax you give in your example would create problems when you spell a column name wrong)...
with cte as (
select '2012-04-04' as student_dob, '%test1%' as student_pat
union all
select '2012-05-04', '%test2%'
union all
select '2012-07-04', '%test3%'
union all
select '2012-05-11', '%test-n%'
)
select *
from students s
inner join cte c
on s.student_dob = c.student_dob and s.student_name like c.student_pat
arguably that's not a lot more readable, but taking a lead from that, you can just store those in a table or go through temporary table, like Roy suggested.
Also it's not great idea to make a group by student id and select also something else like you did in 2nd query.
I have two tables.
I query like this:
SELECT * FROM (
Select requester_name,receiver_name from poem_authors_follow_requests as one
UNION
Select requester_name,receiver_name from poem_authors_friend_requests as two
) as u
where (LOWER(requester_name)=LOWER('user1') or LOWER(receiver_name)=LOWER('user1'))
I am using UNION because i want to get distinct values for each user if a user exists in the first table and in the second.
For example:
table1
nameofuser
peter
table2
nameofuser
peter
if peter is on either table i should get the name one time because it exists on both tables.
Still i get one row from first table and a second from table number two. What is wrong?
Any help appreciated.
There are two problems with your SQL:
(THis is not the question, but should be considered) by using WHERE over the UNION instead of the tables, you create a performance nightmare: MySQL will create a temporary table containing the UNION, then query it over the WHERE. Using a calculation on a field (LOWER(requester_name)) makes this even worse.
The reason you get two rows is, that UNION DISTINCT will only suppress real duplicates, so the tuple (someuser,peter) and the tuple (someotheruser, peter) will result in duplication.
Edit
To make (someuser, peter) a duplicate of (peter, someuser) you could use:
SELECT
IF(requester_name='peter', receiver_name, requester_name) AS otheruser
FROM
...
UNION
SELECT
IF(requester_name='peter', receiver_name, requester_name) AS otheruser
FROM
...
So you only select someuser which you already know : peter
You need the where clause on both selects:
select requester_name, receiver_name
from poem_authors_follow_requests
where LOWER(requester_name) = LOWER('user1') or LOWER(receiver_name) = LOWER('user1')
union
select requester_name, receiver_name
from poem_authors_friend_requests
where LOWER(requester_name) = LOWER('user1') or LOWER(receiver_name) = LOWER('user1')
The two queries are independent of each other, so you shouldn't try to connect them other than by union.
You can use UNION if you want to select rows one after the other from several tables or several sets of rows from a single table all as a single result set.
UNION is available as of MySQL 4.0. This section illustrates how to use it.
Suppose you have two tables that list prospective and actual customers, a third that lists vendors from whom you purchase supplies, and you want to create a single mailing list by merging names and addresses from all three tables. UNION provides a way to do this. Assume the three tables have the following contents:
http://w3webtutorial.blogspot.com/2013/11/union-in-mysql.html
You are doing the union before and then applying the where clause. So you would get a unique combination of "requester_name,receiver_name" and then the where clause would apply. Apply the where clause in each select...
Select requester_name,receiver_name from poem_authors_follow_requests
where (LOWER(requester_name)=LOWER('user1')
or LOWER(receiver_name)=LOWER('user1'))
UNION
Select requester_name,receiver_name from poem_authors_friend_requests
where (LOWER(requester_name)=LOWER('user1')
or LOWER(receiver_name)=LOWER('user1'))
In your where statement, reference the alias "u" for each field refence in your where statement.
So the beginning of your where statement would be like: where (LOWER(u.requester_name) = ...
This is simlar to the answer you can see in: WHERE statement after a UNION in SQL?
You should be able to use the INTERSECT keyword instead of doing a nested query on a UNION.
SELECT member_id, name FROM a
INTERSECT
SELECT member_id, name FROM b
can simply be rewritten to
SELECT a.member_id, a.name
FROM a INNER JOIN b
USING (member_id, name)
http://www.bitbybit.dk/carsten/blog/?p=71
I have to do a search engine of website with a lot of access. This search will have to select information of 5 tables before result the records.
I could make 5 query as SELECT * FROM table1 like ...
But I was wondering if I could use an VIEW to do just one Query. (to get a better performance)
I have already checked informations about how to creat a view but its not so clear how to do que consult and how to manipulate the returned records.
Can anyone give me a simple example of how I should create (SQL Syntax) this VIEW and how I would do the search Query.
About the Tables as Example:
Table 1 id | title | description
Table 2 id | name | tags
Table 3 id | name | address
Table 4 id | product | price
I need to check all the fields.
Regards,
Looks like the 5 tables are entirely unrelated - they're not a good candidate for creating a view. For a view to work, you'd need all columns in all tables to be of a similar datatype, and presumably "price" is a numerical column, whereas the others are varieties of varchar.
You could, of course, manipulate the "select" in the view to modify that, but then you end up with a view that makes no sense.
For instance (not checked for syntax, I haven't got SQL on my netbook)
create view SEARCH_VIEW
as
select 'T1' as source, id, title, description
from t1
union
select 'T2' as source, id , name, tags
from t2
union
select 'T3' as source, id, name, address
from t3
union
select 'T4', id, product, convert(varchar, price)
from t4
But then the resulting table would make no sense.
I'd stay with the separate queries; this also allows you to make decisions about relevance (a hit in "name" may be more relevant than in "tags", for instance).
Finally, you may need to look into free text indexing if you want to do text searches on large tables.
Views cannot return more than one result set. If you are currently returning 5 different result sets, one for each select statement, then a View is not going to help you.
If you are okay combining the result sets into one as shown below, then the View will help:
select title as col1 , description as col2 from table1
union
select name as col1 , tags as col2 from table2
union
select name as col1 , address as col2 from table3
union
select product as col1 , price as col2 from table4
Note: If price is not the same data type as description, tags and address in table1, table2, and table3 respectively, you'd probably need to cast it to the same data type as the other columns in the other tables. I am not sure what will be the coercion used by MySQL in this case but to be on the safe side, I would cast it.
On MySQL Views are created as follows:
CREATE VIEW test.v AS
select title as col1 , description as col2 from table1
union
select name as col1 , tags as col2 from table2
union --... etc
Then you can query it the same way you do it with a regular table; for example: select col1, col2 from view_name where <condition>
If you can't combine everything in one result set, a stored procedure is the way to go. Just write a stored procedure that runs the 5 select statements in sequence and you call it from the front-end passing, I imagine, some sort of search parameter. The specifics on how to call this stored proc depends on the language/technology you are using.