How to resolve an id by an foreign table - sql

I want to resolve an ID by another table, where the name of this id is stored.
SELECT d.id_data, string_agg(s.name_last,', ') AS authors, d.title, i.name
FROM data d, institution i, staffs s
WHERE d.id_staffs = s.id_staffs
AND d.id_institution = i.id_institution
GROUP BY d.id_data limit 100 ;
But how can I get the name of my Institution. I want that the SELECT shows me the institution name, which has stored the data. Something like that
id_data | authors | title | name
----------------------------------------------------------------
1 |Mustermann, Musterfrau | sunmaker | university cologne
2 |Schmidt, Müller | dry age | university berlin
I just need to resolve the id of the institution to his name.

Always use proper, explicit, standard JOIN syntax. Never use commas in the FROM clause.
Presumably, you want something like this:
SELECT d.id_data, string_agg(s.name_last,', ') AS authors,
d.title, i.name
FROM data d JOIN
institution i
ON d.id_staffs = s.id_staffs JOIN
staffs s
ON d.id_institution = i.id_institution
GROUP BY d.id_data, d.title, i.name
LIMIT 100 ;
That is, fix the GROUP BY to have all the unaggregated columns.

Related

SQL Return Column value as Enum - GetValue() field from another Column

Here are the two tables;
Cathegories
----------------------------------------
Cathegory (tinyint) | Name (nvarchar)
----------------------------------------
0 | Field
1 | Mountain
2 | River
----------------------------------------
Places
------------------------------------------
Name (nvarchar) | Cathegory(tinyint)
------------------------------------------
Abc | 2
Xyz | 1
------------------------------------------
When I want to retrieve the Places listing Names and their Cathegories not in the int format but according to the description in Cathegories.
So retrieving Abc I want it like this;
"River" instead the '2'
Please use below query,
select c.name as place, p.name as name from Cathegories c
inner join Places p
on (c.Cathegory = p.Cathegory);
You need to join two table on cathegory as shown below.
select
p.name as places,
c.name as category_name
from places p
join cathegories c
on p.cathegory = c.cathegory
Here is a version of multiple JOIN statements based on the accepted answer:
SELECT
ColumnUserViews,
C.Cathegory AS VCathegory,
ColumnUserPoints,
T.Description AS VTag1,
TT.Description AS VTag2
FROM dbo.Users U
JOIN dbo.Cathegories C ON U.Cathegory = C.Cathegory
JOIN dbo.Tags T ON U.Tag1 = T.Tag
JOIN dbo.Tags TT ON U.Tag2 = TT.Tag
The keyword U defines physical table Users, T Tags, and TT also Tags (free to rename).
VCathegory is a new virtual Column to be retrieved which holds the value of Users.Cathegory translated into Cathegories.Description ('s string equivalent) as per this current scheme.

Oracle SQL - Return rows with a value based on multiple values in a second field

I need to return the rows that contain the employee names (in one field) who are only classified as Managers (not as Workers, or as Managers and Workers).
Managers and Workers values are in a second field.
So it might look like this:
+----------+------------+
| 'Miller' | 'Manager' |
| 'Jones' | 'Manager' |
| 'Jones' | 'Worker' |
+----------+------------+
In this instance I just want it to return 'Miller'.
I can get one or both, but not the ones where an employee is only classified as a Manager.
Any thoughts?
One method uses aggregation:
select name
from t
group by name
having min(classification) = max(classification) and min(classification) = 'manager';
Count the number of titles. If they have a title of 'Manager' and there's only one title, select the individual:
SELECT *
FROM PEOPLE p
INNER JOIN (SELECT NAME, COUNT(TITLE) AS TITLE_COUNT
FROM PEOPLE
GROUP BY NAME) c
ON c.NAME = p.NAME
WHERE p.TITLE = 'Manager' AND
c.TITLE_COUNT = 1;
dbfiddle here
Method with a subquery which should work well when there are not only 'Managers' and 'Workers' in the table:
SELECT t1.name FROM t t1
WHERE
t1.classification='Manager'
AND NOT EXISTS (
SELECT 1 FROM t t2 WHERE t1.name=t2.name AND t2.classification='Worker'
)

How to use LISTAGG to concatenate from multiple rows?

I have report query along these lines in APEX 5.0:
WITH inner_table AS
( select distinct
i.ID
,i.name
,i.lastname
,case i.gender
when 'm' then 'Male'
when 'f' then 'Female'
end gender
,i.username
,b.name region
,i.address
,i.city city
,i.EMAIL
,r.name as "ROLE"
,ie.address as "region_location"
,case
when i.gender='m' THEN 'blue'
when i.gender='f' THEN '#F6358A'
END i_color
,b.course as COURSE
,si.city UNIVERSITY
,case
when i.id in (select app_user from scholarship) then 'check'
else 'close'
end as scholarship,
case
when i.id in (select ieur.app_user from ie_user_role ieur where role=4) then 'Admin'
else ''
end admin,
apex_item.checkbox(10, i.id, 'UNCHECKED onclick="highlightRow(this);"') as Del_usr
from app_users i left join regions b on (i.region=b.id)
left join ie_user_role ur on (i.id = ur.app_user)
left join ie_roles r on(ur.role = r.id)
left join user_house uh on (i.id=uh.app_user)
left join reg_location ie on (uh.house=ie.id)
left join study_list sl on i.id = sl.insan
left join study_institute si on sl.institute = si.id
left join course c on sl.course = c.id
where i.is_active='Y'
order by
i.name,i.lastname,i.username,region, city, i.EMAIL)
SELECT * FROM inner_table where (scholarship = :P5_SCHOLARSHIP or :P5_SCHOLARSHIP is null)
I might get results like this:
|---------------------|------------------|-------|------------------|
| Name | Lastname | ... | Course |
|---------------------|------------------|-------|------------------|
| Some | User | ... | Course1 |
|---------------------|------------------|-------|------------------|
| Some | User | ... | Course2 |
|---------------------|------------------|-------|------------------|
But I would like to achieve enlisted courses in same row, that was repeating previously, so:
|---------------------|------------------|-------|------------------|
| Name | Lastname | ... | Course |
|---------------------|------------------|-------|------------------|
| Some | User | ... | Course1, Course2 |
|---------------------|------------------|-------|------------------|
I tried using LISTAGG, and I didn't note down my attempts, so unfortunately I can't post that now. I basically tried:
,LISTAGG(b.course, ', ') within group (order by b.course) as COURSE
Then adding GROUP BY using COURSE, but in that case whole query is affected by GROUP BY and I have to apply other columns correctly, right? Otherwise its resulting in "ORA-00937: not a single-group group function". I got lost a bit there.
Other thing I tried is using a subquery table with same LISTAGG line above, and got wanted output from subquery, but then joining to the rest of the query didn't provide expected results.
I think I could use a bit of SQL help here for LISTAGG when joining multiple tables.
Thanks.
When you use an aggregate function (that collapses multiple rows into one) you need a GROUP BY clause, so you'd need something like this:
SELECT i.username,
LISTAGG( c.course, ', ' ) WITHIN GROUP ORDER BY ( c.course )
FROM app_users i
...
LEFT JOIN course c on sl.course = c.id
GROUP BY i.username
Basically, anything that's not being aggregated, needs to be in the GROUP BY clause. Try it in a much simpler query until you get the hang of it, then make your big one.
What you want is LISTAGG with an analytical window function. Then remove duplicates using distinct. Here is my sample result/ data: http://sqlfiddle.com/#!4/6e8e3f/3
Select DISTINCT name, last_name, other columns,
LISTAGG(course, ', ') WITHIN GROUP (ORDER BY course)
OVER (PARTITION BY name, last_name) as "Course"
FROM inner_table;

SQL : get one particular book owner

I have a Student table with columns like this:
| email (PK) | name |
I have a book table with columns as such:
| bookid(PK) | title |
I have a copy table which have copies of books people own
| emailofOwner(FK to student.email) | bookid(FK to book.bookid) |
A student can of course own multiple books. My aim is to find names of students who own only 1 such book and nothing else BUT with a bookid = 3;
My attempt to get people who own only 1 book.
select c.emailofOwner
from copy c
group by c.emailofOwner
having count(*) = 1 ;
SELECT t1.name
FROM student t1
INNER JOIN
(
SELECT emailofOwner
FROM copy
GROUP BY emailofOwner
HAVING COUNT(DISTINCT bookid) = 1 AND MAX(bookid) = 3
) t2
ON t1.email = t2.emailofOwner
The above query uses a subquery to restrict to students who own one and only one book whose ID is 3. The subquery is identical to your attempt except that it adds the restriction that the max book ID is 3. In this case, since there will only be one book per retained group, this is simply checking the value of the book ID.
To get students with only
select s.name, s.email, count(*) as numBooks
from student s, copy c
where s.email = c.emailOfOwner
group by email
having count(*) = 1
And people with book 3 and ONLY book 3:
select s.name, s.email, count(*) as numBooks
from student s, copy c
where s.email = c.emailOfOwner
group by email
having count(*) = 1 and min(bookId) = 3;
Check out this SQL Fiddle.

Select Query Joining 3 Tables

I've 3 Tables
Personel : id, name
Department : id, name
Match_Dept_Per : dept_id, pers_id, workInfo
Foreign Keys :
dept_id --> Department.id
pers_id --> Personel.id
Example Data :
Personel :
1, Emir Civas
2, Sercan Tuncay
Department :
1, Sales
2, Planning
Match_Dept_Per :
1,1,Manager
What I'm trying to do is, listing peoples names, their department names and workInfos like:
ID | Pers. Name | Dept Name | Work Info
---------------------------------------
1 | Emir Civas | Sales | Manager
I can do this with a simple select query:
select p.id, p.name, d.name, m.workInfo
from personel p, department d, match_dept_per m
where p.id = m.pers_id and d.id = m.dept_id;
Here is sample fiddle of my schema and this query.
However what I need is to display other persons that their id's are not inserted to match_dept_per table. And Set "Unknown" As the Null Values. Like:
ID | Pers. Name | Dept Name | Work Info
------------------------------------------
1 | Emir Civas | Sales | Manager
2 | Sercan Tuncay | Unknown | Unknown
Since I'm Using Match_Dept_Per Table, If Personel ID isn't Added, I can't do anything.
Any suggestions ?
Use left outer join to include all persons even if they are not associated with the other tables:
select p.id,
p.name,
ifnull(d.name, 'Unknown') DepName,
ifnull(m.workInfo, 'Unknown') workInfo
from personel p
left outer join match_dept_per m
on p.id = m.pers_id
left outer join department d
on d.id = m.dept_id
Here is a demo fiddle.
As you seem to use MS SQL, you might need to use isnull() instead of ifnull(). But I would ommit that anyway because I think it's better to have a NULL in the code where you use the data (Java, C#, whatever). You can control the output there.