Selecting distinct values from joined results in Mysql - mysql

I am trying to access complete data from two tables in mysql and then find distinct values of a column from the resulting set. tried doing with nested query as follows :-
Select distinct s.BlockName
from (SELECT *
FROM constucted
LEFT JOIN required ON constucted.BlockName = required.BlockName
UNION
SELECT *
FROM constucted
RIGHT JOIN required ON constucted.BlockName = required.BlockName
) s
As mentioned in Stackoverflow Reference
and also tried using the with keyword as follows :-
WITH CTE
AS
(
SELECT *
FROM constucted
LEFT JOIN required ON constucted.BlockName = required.BlockName
UNION
SELECT *
FROM constucted
RIGHT JOIN required ON constucted.BlockName = required.BlockName
)
SELECT DISTINCT BlockName
FROM CTE
But unable to find the distinct value for the column BlockName unable to prepare a query for the same.

Your query would seem to be more simply written as:
select BlockName
from constructed
union -- intentional to remove duplicates
select BlockName
from required;

Related

Save the intermediate result of SQL query

I am wondering if there is any way to save the intermediate result or tables in SQL. For example assume you have two different SQL statements that in the first statement you join two tables, then you want to see how many rows the resulting table has. I know there are many ways to do this but I am interested in seeing how this can be done sequentially. Consider the following example:
select * from order_table left join customer_table on order_table.id = customer_table.id
Then I want to see count of number of rows (as an easy example)
select count(*) from table
But I do not know what this table should be. How may I save the result of above query in some logical table or how to refer to what was created before in SQL.
You can use WITH like below:
WITH resultTable as ( select * from order_table left join customer_table on order_table.id = customer_table.id )
select count(*) from resultTable
For this particular example you can simply wrap the original query in a sub-query:
select count(*)
from (
select *
from order_table
left join customer_table on order_table.id = customer_table.id
) as x
If you want to store the result in a physical table (temporary or permanent) then the procedure varies for each rdbms. In SQL Server for example you would use SELECT INTO:
select *
into #temp_table
from order_table
left join customer_table on order_table.id = customer_table.id
you can also use CTE. for your question it will be:
;
with table1 as (
select * from order_table
left join customer_table on order_table.id = customer_table.id
)
select count(*) from table1
GO

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

How to use UNION and GROUP_CONCAT together

I have a problem with the correct syntax to use UNION and GROUP_CONCAT in this situation:
I have 4 tables:
base: Is the main table with a lot of columns.
mm: Is a mm table that points to the next two tables using a 'tablenames' field.
t1 and t2 that stores data related.
Records in 'base' tables can have many related records in t1 and t2 through the mm table.
I'm creating a VIEW in MySQL and I need all those related records are displayed in a single column separated by commas.
This is the base MySQL code:
SELECT base.uid, t1.nombre_es
FROM base
INNER JOIN mm
ON mm.uid_local=base.uid
INNER JOIN t1
ON mm.uid_foreign=t1.uid WHERE mm.tablenames = 't1'
UNION
SELECT base.uid, t2.nombre_es
FROM base
INNER JOIN mm
ON mm.uid_local=base.uid
INNER JOIN t2
ON mm.uid_foreign=t2.uid WHERE mm.tablenames = 't2'
Thanks in advance.
I could do it using two VIEWS, the first using the code above with the name 'viewtest", and the second with this code:
SELECT base.uid,
GROUP_CONCAT(DISTINCT vi.nombre_es ORDER BY vi.nombre_es SEPARATOR ',') as nombre
FROM base
INNER JOIN viewtest as vi
ON vi.uid=base.uid
GROUP BY uid
Now the question is ¿How can I join this two views in a single view?
You can use derived tables from queries. Next is an example of how you can use them.
SELECT GROUP_CONCAT( f )
FROM (
SELECT 1 AS f # <-- QUERY #1
UNION
SELECT 2 AS f # <-- QUERY #2
UNION
SELECT 3 AS f # <-- QUERY #3
) AS T
Basically, you can use any SELECT query as an aliased table. Then, you can apply any aggregate functions you need to that aliased query.

How to easily get the unmatched condition in 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.