filter sql rows using update statement - mysql

I am trying to write a query which can get invalid refby(is related to id), please check following db structure...
| id | acnumber | refby |
+----+-----------+--------+
| 1 | ac01 | 2 |
+----+-----------+--------+
| 2 | ac02 | 1 |
+----+-----------+--------+
| 3 | ac03 | 5 |
+----+-----------+--------+
As you can find there is no id with value of 5 in above table so query must return 3rd row as result.
I have tried...
SELECT * FROM tbl.members WHERE refby != (SELECT id FROM tbl.members WHERE id = refby)
But this is not giving correct results, please help, thanks.

SELECT * FROM members WHERE refby not in (SELECT id FROM members)
This should solve your problem

You can try this using not in:-
SELECT * FROM tbl.members WHERE refby not in (SELECT id FROM members)

This should be a LEFT JOIN, NOT IN is slow on large tables... assuming id and refid is an PRIMARY KEY or UNIQUE key (read unique within your dataset) then this query should return the same results.
SELECT
*
FROM
members members1
LEFT JOIN
members members2
ON members1.id = members2.refby
WHERE members2.id IS NULL
check the sqlfriddle http://sqlfiddle.com/#!2/05731/1

Related

In mysql how can I get only rows from one table which do not link to any rows in another table with a specific ID

I have two tables with the following structures (unnecessary columns trimmed out)
----------------- ---------------------
| mod_personnel | | mod_skills |
| | | |
| - prs_id | | - prs_id |
| - name | | - skl_id |
----------------- | |
---------------------
There may be 0 to many rows in the skills table for each prs_id
What I want is all the personnel records which do NOT have an associated skill record with skill_id 1.
In plain English "I want all the people who do not have the skill x".
Currently, I have only been able to do it with the following nested select. But I am hoping to find a faster way.
SELECT * FROM `mod_personnel` WHERE `prs_id` NOT IN (
SELECT `prs_id` FROM `mod_skills` WHERE `skl_id` = 1 )
This may be faster:
SELECT `mod_personnel`.*
FROM `mod_personnel`
left outer join `mod_skills`
on `mod_skills`.`prs_id` = `mod_personnel`.`prs_id`
and `mod_skills`.`skl_id` = 1
WHERE `mod_skills`.`prs_id` is null;
Using a NOT EXISTS might be faster.
SELECT *
FROM `mod_personnel` p
WHERE NOT EXISTS (SELECT *
FROM `mod_skills` s
WHERE s.`prs_id` = p.`prs_id`
AND s.`skl_id` = 1 );

SQL Use Result from one Query for another Query

This is an excerpt from one table:
| id | type | other_id | def_id | ref_def_id|
| 1 | int | NULL | 5 | NULL |
| 2 | string | NULL | 5 | NULL |
| 3 | int | NULL | 5 | NULL |
| 20 | ref | 3 | NULL | 5 |
| 21 | ref | 4 | NULL | 5 |
| 22 | ref | 5 | NULL | 5 |
What I want is to find entries with type ref. Then I would for example have this one entry in my result:
| 22 | ref | 5 | NULL | 5 |
The problem I am facing is that I now want to combine this entry with other entries of the same table where def_id = 5.
So I would get all entries with def_id = 5 for this specific ref type as result. I somehow need the output from my first query, check what the ref_def_id is and then make another query for this id.
I really have problems to understand how to proceed. Any input is much appreciated.
If I understand correctly you need to find rows with a type of 'ref' and then use the values in their ref_def_id columns to get the rows with the same values in def_id. In that case you need to use a subquery for getting the rows with 'ref' type and combine it using either IN or EXISTS:
select *
from YourTable
where def_id in (select ref_def_id from YourTable where type='ref');
select *
from YourTable
where exists (select * from YourTable yt
where yt.ref_def_id=YourTable.def_id and yt.type='ref')
Both queries are equivalent, IN is easier to understand at first sight but EXISTS allow more complex conditions (for example you can use more than one column for combining with the subquery).
Edit: since you comment that you need also the id from the 'ref' rows then you need to use a subquery:
select source_id, YourTable.*
from YourTable
join (select id as source_id, ref_def_id
from YourTable
where type='ref')
as refs on refs.ref_def_id=YourTable.def_id
order by source_id, id;
With this for each 'ref' row you would get all the rows with the associated ref_id.
use below query to get column from sub query.
select a.ref_def_id
from (select ref_def_id from YourTable where type='ref') as a;
What you are looking for is a subquery or even better a join operation.
Have a look here: http://www.mysqltutorial.org/mysql-left-join.aspx
Joins / the left join allows you to combine rows of tables within one query on a given condition. The condition could be id = 5 for your purpose.
You would seem to want aggregation:
select max(id) as id, type, max(other_id) as other_id,
max(def_id) as def_id, ref_def_id
from t
where type = 'ref'
group by type, ref_def_id

Select count with value from different tables

I want to count all entries in one table grouped by the user id.
This is the query I used which works fine.
select uuid_mapping_id, count(*) from t_message group by uuid_mapping_id;
and these are the results:
+-----------------+----------+
| uuid_mapping_id | count(*) |
+-----------------+----------+
| 1 | 65 |
| 4 | 277 |
Now I would like to display the actual user name, instead of the ID.
To achieve this I would need the help of two different tables.
The table t_uuid_mapping which has two columns:
uid_mapping_id, which equals uuid_mapping_id in the other table.
And f_uuid which is also unique but completely different.
f_uuid can also be found in another table t_abook which also contains the names in the column f_name.
The result I am looking for should be:
+-----------------+----------+
| f_name | count(*) |
+-----------------+----------+
| admin | 65 |
| user1 | 277 |
I am new to the database topic and understand that this could be achieved by using JOIN in the query, but to be honest I did not completely understand this yet.
if I understand you correctly:
SELECT tm.f_name, COUNT(*) as count
FROM t_message tm
LEFT JOIN t_abook ta ON (tm.uuid_mapping_id = ta.uid_mapping_id)
GROUP BY tm.f_name

SELECT from Union x 3 using filter of another table

Background
I have a web application which must remove entries from other tables, filtered through a selection of 'tielists' from table 1 -> item_table 1, table 2, table 3.... now basically my result set is going to be filthy big unless I use a filter statement from another table, using a user_id... so can someone please help me structure my statement as needed? TY!
Tables
cars_belonging_to_user
-----------------------------
ID | user_id | make | model
----------------------------
1 | 1 | Toyota | Camry
2 | 1 |Infinity| Q55
3 | 1 | DMC | DeLorean
4 | 2 | Acura | RSX
Okay, Now the three 'tielists'
name:tielist_one
----------------------------
id | id_of_car | id_x | id_y|
1 | 1 | 12 | 22 |
2 | 2 | 23 | 32 |
-----------------------------
name:tielist_two
-------------------------------
id | id_of_car | id_x | id_z|
1 | 3 | 32 | 22 |
-----------------------------
name: tielist_three
id | id_of_car | id_x | id_a|
1 | 4 | 45 | 2 |
------------------------------
Result Set and Code
echo name_of_tielist_table
// I can structure if statements to echo result sets based upon the name
// Future Methodology: if car_id is in tielist_one, delete id_x from x_table, delete id_y from y_table...
// My output should be a double select base:
--SELECT * tielists from WHERE car_id is 1... output name of tielist... then
--SELECT * from specific_tielist where car_id is 1.....delete x_table, delete y_table...
Considering the list will be massive, and the tielist equally long, I must filter the results where car_id(id) = $variable && user_id = $id....
Side Notes
Only one car id will appear once in any single tielist..
This select statement MUST be filtered with user_id = $variable... (and remember, i'm looking for which car id too)
I MUST HAVE THE NAME of the tielist it comes from able to be echo'd into a variable...
I will only be looking for one single id_of_car at any given time, because this select will be contained in a foreach loop.
I was thinking a union all items would do the trick to select the row, but how can I get the name of the tielist the row is in, and how can the filter be used from the user_id row
If you want performance, I would suggest left outer join instead of union all. This will allow the query to make efficient use of indexes for your purpose.
Based on what you say, a car is in exactly one of the lists. This is important for this method to work. Here is the SQL:
select cu.*,
coalesce(tl1.id_x, tl2.id_x, tl3.id_x) as id_x,
tl1.y, tl2.idz, tl3.id_a,
(case when tl1.id is not null then 'One'
when tl2.id is not null then 'Two'
when tl3.id is not null then 'Three'
end) as TieList
from Cars_Belonging_To_User cu left ouer join
TieList_One tl1
on cu.id_of_car = tl1.id_of_car left outer join
TieList_Two tl2
on cu.id_of_car = tl2.id_of_car left outer join
TieList_Three tl3
on cu.id_of_car = tl3.id_of_car;
You can then add a where clause to filter as you need.
If you have an index on id_of_car for each tielist table, then the performance should be quite good. If the where clause uses an index on the first table, then the joins and where should all be using indexes, and the query will be quite fast.

Mysql select IN return null if id not exists

I have a table like this:
+----+---------+---------+
| Id | column1 | column2 |
+----+---------+---------+
| 1 | a | b |
| 2 | a | b |
+----+---------+---------+
and a query like this SELECT * FROM table WHERE id IN (1,2,3)
what query do I need to get a result like this(I need to get null values for nonexisten id's):
+----+---------+---------+
| Id | column1 | column2 |
+----+---------+---------+
| 1 | a | b |
| 2 | a | b |
| 3 | null | null |
+----+---------+---------+
EDIT
Thanks for the responses so far.
Is there a more 'dynamic way' to do this, the query above it's just an example.
In reality I need to check around 1000 id's!
You could use something like this:
SELECT ids.ID, your_table.column1, your_table.column2
FROM
(SELECT 1 as ID
UNION ALL SELECT 2
UNION ALL SELECT 3) ids left join your_table
on ids.ID = your_table.ID
First subquery returns each value you need in a different row. Then you can try to join each row with your_table. If you use a left join, all values from the first subquery are shown, and if there's a match with your_table, values from your_table are shown, otherwise you will get nulls.
That is not the way SQL works unfortunately. I would think it would be pretty trivial for your application to determine the differences between the id's it asked for and the id's returned.
So rather than hack or some weird query to mock up your result, why not have your application handle it?
I still can't understand though what the use case might be to where you would be querying rows on teh database by id's that may or may not exist.