How to easily get the unmatched condition in mysql - mysql

I have a "server" table which has a column named 'SN' in mysql, when do query to retrive servers with some sns from 'sn1' to 'sn10000', we can:
select * from server where sn in ('sn1','sn2','sn3',...'sn10000');
If there is only one sn in 'sn1'-'sn10000' which not exists in database, then the query above will retrive 9999 rows of result.
The question is how can I easily get which one in 'sn1'-'sn10000' is not exists in database except the additional work, such as handling the result with shell script etc.
I have an ugly sql like below can use:
select * from (select 'sn1' as sn
union select 'sn2'
union select 'sn3'
....
union select 'sn10000') as SN
where not exists (select id from server where server.sn=SN.sn);
Is Anyone has other better methods? Thanks.

Your query is perfectly fine for the intended use, but on MySQL the NOT IN and LEFT JOIN/IS NULL are more effecient that NOT EXISTS. Here are your alternatives:
NOT IN
SELECT *
FROM ( SELECT 'sn1' as sn
UNION ALL SELECT 'sn2'
UNION ALL SELECT 'sn3'
....
UNION ALL SELECT 'sn10000') as SN
WHERE sn.sn NOT IN (SELECT s.id FROM SERVER s)
LEFT JOIN/IS NULL
SELECT s.id
FROM SERVER s
LEFT JOIN ( SELECT 'sn1' as sn
UNION ALL SELECT 'sn2'
UNION ALL SELECT 'sn3'
....
UNION ALL SELECT 'sn10000') as SN ON SN.sn = s.id
WHERE sn.sn IS NULL
You might notice I used UNION ALL, rather than UNION - UNION removes duplicates (which won't happen in your example), making it slower so UNION ALL is a better choice.

Stick your sn1, sn2, sn3... sn10000 values in a temporary table, and then use Joins.
Select server.* from server inner join tempt on (tempt.value = server.sn)
will give you the ones that match, where as
Select sn.* from server right outer join tempt on (tempt.value = server.sn)
where server.somefield is Null
should take care of finding the missing ones.

Related

How to correct result with Union All

I am fetching the result of Union All but Only 1 query is running.
select user_leftside as SId from tbl_user inner join (select #sid:=(select group_concat(user_leftside,',',user_rightside) from tbl_user where find_in_set(user_id, #nsid)) , #nsid:=#sid as fset from tbl_user, (select #nsid:='first_left_child',#sid='')v )gr on find_in_set(user_leftside,fset) where user_leftside <> ''
UNION ALL
select user_rightside as SId from tbl_user inner join (select #sid:=(select group_concat(user_leftside,',',user_rightside) from tbl_user where find_in_set(user_id, #nsid)) , #nsid:=#sid as fset from tbl_user, (select #nsid:='first_left_child',#sid='')v )gr on find_in_set(user_rightside,fset) where user_rightside <> ''
How can i get the result with Union All. This is tree related query
Use different variable names inside those two subqueries.
The use of variables in MySQL queries is always risky: the order of evaluation is not guaranteed. These subqueries might even perform evaluations in parallel and so you must avoid spillover of variable values from one to the other.

SQL: selecting the set of A not B

I have Two tables: left one is users_projects, right one is projects:
I want to select the projects that user 3 is not participating in (only p_ID 5 and 7).
I've tried SELECT * FROM users_projects up INNER JOIN projects p ON p.p_ID=up.p_ID WHERE up.u_ID!=3
but that also returns me p_ID 1 which both user 2 and 3 are a part of.
Thanks for your help!
A solution with LEFT JOIN:
SELECT
*
FROM
projects p LEFT JOIN users_projects up ON (p.p_ID = up.p_ID AND up.u_ID = 3)
WHERE
up.u_ID IS NULL
Basically select all Projects and join them with the user_projects of the desired user. Left join makes all rows from the project table appear even if the is no corresponding row in the users_projects table. These rows have all fields from the users_projects set to NULL, so we can just select those.
This is not a JOIN query, but a query with a non-correlated sub-select with a NOT IN() predicate.
I hope the columns of the projects table are enough ...
SELECT
*
FROM
( SELECT 1,'Apple' -- input data, don't use in 'real' query
UNION ALL SELECT 5,'Banna' -- input data, don't use in 'real' query
UNION ALL SELECT 7,'Carrot' -- input data, don't use in 'real' query
UNION ALL SELECT 8,'Durian') -- input data, don't use in 'real' query
projects(p_id,p_name)
WHERE p_id NOT IN (
SELECT
p_id
FROM
( SELECT 2,1 -- input data, don't use in 'real' query
UNION ALL SELECT 2,5 -- input data, don't use in 'real' query
UNION ALL SELECT 2,7 -- input data, don't use in 'real' query
UNION ALL SELECT 3,1 -- input data, don't use in 'real' query
UNION ALL SELECT 3,8) -- input data, don't use in 'real' query
users_projects(u_id,p_id)
WHERE u_id=3
)
;
p_id|p_name
7|Carrot
5|Banna

Mysql Union in different columns

I have the following query
SELECT *
FROM(
(SELECT
MAX(c.start_time) as start_1
FROM
c1 c)
UNION ALL
(SELECT
MAX(cc.created_at) as ccmax
FROM
cc1)
) as t
I'd like to have the result in a table with 2 columns start_1 and cmax instead of the single column I get with all the different results listed.
How should I do it? I ended up in a subselect believing this would have done the job.
For the data to be in two columns you would have to use a sub select.
SELECT
MAX(c1.start_time) as start_1, (SELECT MAX(cc1.created_at) FROM cc1) as ccmax
FROM c1

Creating view in mysql with union all but all records are being shown under 1 column

I'm trying to create a view in MYSQL but when using Union ALL it is being shown underneath 1 column. when I try to add column names it simply says that the amount of columns and results dont match
use TestDB;
DROP VIEW if exists auditTableView;
Create view auditTableView
AS
select usernames.username from usernames LEFT JOIN auditTable on usernames.ID = auditTable.userID
Union ALL
select actionDesc.functionName from actionDesc LEFT JOIN auditTable on actionDesc.actionID = auditTable.actionID
Union all
SELECT timestamp from auditTable;
SELECT * FROM auditTableView;
From what can be gathered of your schema, it looks like you want to do an inner join from the auditTable to your usernames and actionDesc table, and select the username, actionDesc, and timestamp values from there:
use TestDB;
DROP VIEW if exists auditTableView;
Create view auditTableView
AS
select
usernames.username,
actionDesc.functionName,
auditTable.timestamp
from auditTable
inner join usernames
on usernames.ID = auditTable.userID
inner join actionDesc
on actionDesc.actionID = auditTable.actionID;
select * from auditTableView;
With UNION, MySQL uses the column names from the first SELECT statement, and the number of columns must match.
You can do something like this:
SELECT table1.col1, NULL AS col2 FROM table1
UNION ALL
SELECT NULL AS col1, table2.col2 FROM table2

Multiple select statements in Single query

I am generating a report in php (mysql),
ex:
`select count(id) as tot_user from user_table
select count(id) as tot_cat from cat_table
select count(id) as tot_course from course_table`
Like this I have 12 tables.
Can i make it in single query. If i did? Process gets slow?
SELECT (
SELECT COUNT(*)
FROM user_table
) AS tot_user,
(
SELECT COUNT(*)
FROM cat_table
) AS tot_cat,
(
SELECT COUNT(*)
FROM course_table
) AS tot_course
If you use MyISAM tables, the fastest way is querying directly the stats:
select table_name, table_rows
from information_schema.tables
where
table_schema='databasename' and
table_name in ('user_table','cat_table','course_table')
If you have InnoDB you have to query with count() as the reported value in information_schema.tables is wrong.
You can certainly us the a Select Agregation statement as Postulated by Ben James, However This will result in a view with as many columns as you have tables. An alternate method may be as follows:
SELECT COUNT(user_table.id) AS TableCount,'user_table' AS TableSource FROM user_table
UNION SELECT COUNT(cat_table.id) AS TableCount,'cat_table' AS TableSource FROM cat_table
UNION SELECT COUNT(course_table.id) AS TableCount, 'course_table' AS TableSource From course_table;
The Nice thing about an approch like this is that you can explicitly write the Union statements and generate a view or create a temp table to hold values that are added consecutively from a Proc cals using variables in place of your table names. I tend to go more with the latter, but it really depends on personal preference and application. If you are sure the tables will never change, you want the data in a single row format, and you will not be adding tables. stick with Ben James' solution. Otherwise I'd advise flexibility, you can always hack a cross tab struc.
select RTRIM(A.FIELD) from SCHEMA.TABLE A where RTRIM(A.FIELD) = ('10544175A')
UNION
select RTRIM(A.FIELD) from SCHEMA.TABLE A where RTRIM(A.FIELD) = ('10328189B')
UNION
select RTRIM(A.FIELD) from SCHEMA.TABLE A where RTRIM(A.FIELD) = ('103498732H')
SELECT t1.credit,
t2.debit
FROM (SELECT Sum(c.total_amount) AS credit
FROM credit c
WHERE c.status = "a") AS t1,
(SELECT Sum(d.total_amount) AS debit
FROM debit d
WHERE d.status = "a") AS t2
I know this is an old stack but i will post this Multi-SQL select case
SELECT bp.bizid, bp.usrid, bp.website,
ROUND((SELECT SUM(rating) FROM ratings WHERE bizid=bp.bizid)/(SELECT COUNT(*) FROM ratings WHERE bizid=bp.bizid), 1) AS 'ratings',
(SELECT COUNT(*) FROM bzreviews WHERE bizid=bp.bizid) AS 'ttlreviews',
bp.phoneno, als.bizname,
(SELECT COUNT(*) FROM endorsment WHERE bizid=bp.bizid) AS 'endorses'
, als.imgname, bp.`location`, bp.`ownership`,
(SELECT COUNT(*) FROM follows WHERE bizid=bp.bizid) AS 'followers',
bp.categories, bp.openhours, bp.bizdecri FROM bizprofile AS bp
INNER JOIN alluser AS als ON bp.usrid=als.userid
WHERE als.usertype='Business'