Nested sql how to do? - mysql

My input is only userid. How do i combine three tables to get area name. I am pretty sure my syntax is correct
TABLE NAME: userinfo userid PRIMARY KEY
TABLE NAME: userinfo_attarea employee_id FOREIGN KEY userid REFERENCE
userinfo area_id FOREIGN KEY area_id REFERENCE personnel area
TABLE NAME: personnel area area_id PRIMARY KEY areaname
I tried with this but failed,
SELECT areaname FROM userinfo a
INNER JOIN (SELECT *FROM userinfo_attarea b
INNER JOIN SELECT *FROM personnel_area c
ON b.areaid = c.areaid
) b ON a.userid = b.employee_id;

i think you this query will help you
select areaname from personel_area pa inner join
userinfo_attarea ut on pa.area_id=ut.area_id
inner join userinfo ui on ut.employee_id=ui.userid

select b.areaname
from userinfo a INNER JOIN ( SELECT c.areaname FROM ( select *
from userinfo_attarea ) b
INNER JOIN ( select *
from personnel_area ) c on b.areaid = c.areaid
) b on a.userid = b.employee_id;

Your correct syntax would be:
SELECT areaname FROM userinfo a
INNER JOIN (
SELECT * FROM userinfo_attarea b
INNER JOIN personnel_area c
ON b.areaid = c.areaid
) b ON a.userid = b.employee_id;
The SLELECT * FROM on third line is unnecessary.
Also, I strongly recommend proper indentation and correct use of spaces :) (* FROM instead of *FROM). It will increase clarity of your code.
Also, you need to take care of column names, as sometimes they can be ambigious, so you should list them explicitly in inner query and give them unique aliases.

Your syntax is NOT correct. You are using parentheses unnecessarily in the FROM clause. You are NOT using parentheses for subqueries.
The subqueries are entirely unnecessary. In addition, you have a poor choice of table aliases (random letters rather than table abbreviations) and you haven't qualified your table names.
SELECT pa.areaname
FROM userinfo ui INNER JOIN
userinfo_attarea uia
ON uia.employee_id = ui.userid INNER JOIN
personnel_area pa
ON uia.areaid = pa.areaid;

Related

SQL Complex update query filter distinct values only

I have 3 tables with following columns.
Table: A with column: newColumnTyp1, typ2
Table: B with column: typ2, tableC_id_fk
Table: C with column: id, typ1
I wanted to update values in A.newColumnTyp1 from C.typ1 by following logic:
if A.typ2=B.typ2 and B.tableC_id_fk=C.id
the values must be distinct, if any of the conditions above gives multiple results then should be ignored. For example A.typ2=B.typ2 may give multiple result in that case it should be ignored.
edit:
the values must be distinct, if any of the conditions above gives multiple results then take only one value and ignore rest. For example A.typ2=B.typ2 may give multiple result in that case just take any one value and ignore rest because all the results from A.typ2=B.typ2 will have same B.tableC_id_fk.
I have tried:
SELECT DISTINCT C.typ1, B.typ2
FROM C
LEFT JOIN B ON C.id = B.tableC_id_fk
LEFT JOIN A ON B.typ2= A.typ2
it gives me a result of table with two columns typ1,typ2
My logic was, I will then filter this new table and compare the type2 value with A.typ2 and update A.newColumnTyp1
I thought of something like this but was a failure:
update A set newColumnTyp1= (
SELECT C.typ1 from
SELECT DISTINCT C.typ1, B.typ2
FROM C
LEFT JOIN B ON C.id = B.tableC_id_fk
LEFT JOIN A ON B.typ2= A.type2
where A.typ2=B.typ2);
I am thinking of an updateable CTE and window functions:
with cte as (
select a.newColumnTyp1, c.typ1, count(*) over(partition by a.typ2) cnt
from a
inner join b on b.type2 = a.typ2
inner join c on c.id = b.tableC_id_fk
)
update cte
set newColumnTyp1 = typ1
where cnt > 1
Update: if the columns have the same name, then alias one of them:
with cte as (
select a.typ1, c.typ1 typ1c, count(*) over(partition by a.typ2) cnt
from a
inner join b on b.type2 = a.typ2
inner join c on c.id = b.tableC_id_fk
)
update cte
set typ1 = typ1c
where cnt > 1
I think I would approach this as:
update a
set newColumnTyp1 = bc.min_typ1
from (select b.typ2, min(c.typ1) as min_typ1, max(c.typ1) as max_typ1
from b join
c
on b.tableC_id_fk = c.id
group by b.type2
) bc
where bc.typ2 = a.typ2 and
bc.min_typ1 = bc.max_typ1;
The subquery determines whether typ1 is always the same. If so, it is used for updating.
I should note that you might want the most common value assigned, instead of requiring unanimity. If that is what you want, then you can ask another question.

SQL Delete Erro #1064

I don't know why this my DELETE sql command got the error number #1064.
My delete sql:
delete from nit.grades g where
(select id_dep from nit.offers as oo,nit.subjects as s where s.id=oo.id_subject and g.id_offer=oo.id)
!=(select id_dep from nit.students as stu where g.id_student=stu.id);
but this sql Select same where clause is working.
select * from nit.grades g where
(select id_dep from nit.offers as oo,nit.subjects as s where s.id=oo.id_subject and g.id_offer=oo.id)
!=(select id_dep from nit.students as stu where g.id_student=stu.id);
thanks for any help.
the Error message:
The syntax with the alias of the table you use for the delete statement is wrong.
Even more in the subqueries you use the target table and this is not allowed in MySql.
Instead you should use joins.
From your code this is what I understood that you want:
delete g
from nit.grades g
inner join nit.offers oo on g.id_offer = oo.id
inner join nit.subjects s on s.id = oo.id_subject
inner join nit.students st on g.id_student = st.id
where st.id_dep <> s.id_dep
In the WHERE clause I'm not sure if the columns id_dep are qualified correctly because they are not qualified also in your code.
If this is not what you want to do then use your SELECT query which does work (as you say) as a join to the table, provided there is a primary key like id in nit.grades:
delete g
from nit.grades g
inner join (
<your select query here>
) t
on t.id = g.id

Referencing a query result alias in a subquery

This is mostly a SQL syntax / SQL capability question. Why does the following query NOT work:
SELECT * from
(
select m.*, p.type,
from multipliers m
inner join pushes p
on m.push_id = p.id
where p.type = 'CONSTANT'
) AS res1 where res1.push_id = (
select max(push_id) from res1
);
when the following completes without issue:
SELECT * from
(
select m.*, p.type,
from multipliers m
inner join pushes p
on m.push_id = p.id
where p.type = 'CONSTANT'
) AS res1 where res1.push_id = (
select max(push_id) from
(
select m.push_id
from multipliers m
inner join pushes p
on m.push_id = p.id
where p.type = 'CONSTANT'
) AS res2
);
Per the MySQL 5.7 documentation:
Derived tables cannot be correlated subqueries, or contain outer references or references to other tables of the same SELECT.
In other words, you can't reference a derived table in a subquery. The documentation doesn't state this, but it likely acts this way because of an OOO issue since the derived table isn't necessarily processed before the subquery. In MySQL 8.0 you will be able to use a Common Table Expression or CTE, which basically lets you define a reusable derived table before your query, but until then use your second approach.
The first query doesn't work because the selected column doesn't exist. At least if you want to reuse it, it should be res.push_id, anyway it's better to use CTE as Jarlh said in his comment.
WITH
myCte AS ( select m.*, p.type,
from multipliers m
inner join pushes p
on m.push_id = p.id
where p.type = 'CONSTANT')
SELECT * FROM myCte
WHERE myCte.push_id = (SELECT MAX(push_id) FROM myCte)
The error in the 1st query is that a table alias (correlation name) can't be used as a table expression in a FROM.
A table alias with a dot & column identifies a column of a table. (In the predicate logic or relational calculus sense a table alias is a subrow-valued variable.)

Joining 1 table twice in the same SQL query

I have joined 1 table twice on the same query, I keep getting error messages that the 'FROM clause have same exposed names. Even using AS does not seem to work, any ideas or suggestions?
here is the query I am using;
select Contact.*, PERSON.*, address.*
from address
full join Contact
on address.uprn = Contact.uprn
full join PERSON
on Contact.contactno = PERSON.contact
full join address
on address.uprn = PERSON.driveruprn
select Contact.*, PERSON.*, a1.*, a2.*
from address a1
full join Contact
on a1.uprn = Contact.uprn
full join PERSON
on Contact.contactno = PERSON.contact
full join address a2
on a2.uprn = PERSON.driveruprn
, however there is no full join in mysql, workaround
select * from t1
left join t2 ON t1.id = t2.id
union
select * from t1
right join t2 ON t1.id = t2.id
You have to alias the second and subsequent usages of a table:
select ...
from address <---first usage
join contact ...
join person ...
join address AS other_address ... <---second usage
^^^^^^^^^^^^^^^^
Doesn't really matter exactly where you do the aliases, but if you use a single table multiple times, all but ONE of those usages have to have unique aliases.
This is probably because you have same field name in different table
change it like this to make sure fieldnames are unique
SELECT
Contact.field1 as c_field1, Contact.field2 as c_field2 ...,
PERSON.field1 as p_field1, PERSON.field2 as p_field2 ...,
address.field1 as a_field1, address.field2 as a_field2 ...
You need to use a separate alias on each of the address table references in your query to avoid the error you are seeing:
SELECT Contact.*, PERSON.*, a1.*, a2.*
FROM address a1 INNER JOIN Contact ON a1.uprn = Contact.uprn
INNER JOIN PERSON ON Contact.contactno = PERSON.contact
INNER JOIN address a2 ON a2.uprn = PERSON.driveruprn
By the way, there is no FULL JOIN in MySQL, so I have replaced them with INNER JOIN which is likely what you had in mind.

How to give alias to results returned after inner join in mySQL

I need to do a correlated SQL Query and for that purpose i need to provide an alias to outer query which in which I perform an inner join. I am not able to do the alias
SELECT DISTINCT(name)
FROM PERSON
INNER JOIN M_DIRECTOR AS dira
ON (dira.PID = M_DIRECTOR.PID) as dira
WHERE 9 > (
SELECT COUNT(MID) FROM M_DIRECTOR WHERE name = dira.name
) ;
I didn't really understand what you want to do, but I guess
select
distinct p.name,
count(d.MID) cnt
from
hindi2_PERSON p
inner join
hindi2_M_DIRECTOR d
on
p.PID = d.PID
group by
p.name
having count(d.MID) > 9
;
would do what you want
I dont know what you are asking and what you mean by make an alias to an eniter result ?
but you are doing
select distinct(name) as othername
which is you are selecting name and you are giving here othername as an alias
then you retrieve it in result
$row['othername']
There's still something missing. From what you write, there is a field name in the M_DIRECTOR table?
Please show all the tables and attributes involved, use an SQL Fiddle to prepare an example.
SELECT DISTINCT(name)
FROM PERSON as p
INNER JOIN (
SELECT COUNT(MID), PID FROM M_DIRECTOR WHERE name = dira.name
) as d
ON (p.PID = d.PID) ;