How exactly do aliases work in Oracle databases? - sql

I've been dabbling around in sql code and recently was reading up on aliases. I am kind of confused why the following statement does not work:
select id, data from table1 a
inner join
(
select id, data from table2 b,
(
select id, data from table3 e
where b.id = e.id
) c
where b.id = a.id
)d on a.id = d.id
What I want is something like this to work:
select id, data from table1 a
inner join
(
select id, data from
(
select id, data from table3 e
where a.id = e.id
) c
)d on a.id = d.id
Currently my solution doesn't have the WHERE class at the end, meaning all of the table gets fetched.
...
where a.id = e.id
...
My point here, would be to use an ID present in table A in the table E. I'm open to suggestions as to changing the structure, but unfortunately I think the structure will have to stay the same since the actual query is much more complex. This is just an exert from the full query.
EDIT:
I'll try to elaborate as to why I have the current structure.
I have table 1 which contains ID's and text and other columns.
| id | data |
| -------- | ------ |
| table1_1 | text |
| table1_2 | text |
...
The second table contains multiple entries for an ID of table1.
| id | refid | data |
| -------- | -------- | ------ |
| table2_1 | table1_1 | proj1 |
| table2_1 | table1_1 | proj2 |
| table2_2 | table1_1 | proj1 |
| table2_3 | table1_2 | proj5 |
| table2_3 | table1_2 | proj1 |
What I now do is join the entries from table2 to a list of entries with:
LISTAGG(table2.refid, ',') WITHIN GROUP( ORDER BY table2.refid) list_of_projects,
To use this, I need to use group by
My problem was, that I couldn't use the table1.ID in table2.refid.

For better understanding of how sub-queries work, just imagine that database processes them separate from each other.
It means the sub-query
select id, data
from table3 e
where b.id = e.id
will be executed first. There is no alias b in this context -> an error
The next sub-query has the same problem
select id, data from table2 b,
(
select id, data from table3 e
where b.id = e.id
) c
where b.id = a.id
There is no data source called "a" -> another error
And to be honest, using sub-queries in this case is a bad idea. Join is what you need here
I believe something like this will help you out.
select a.id, a.data
from table1 a
inner join table3 e
on a.id = e.id;

From Oracle 12c, you can use CROSS APPLY or a LATERAL join to pass the outer scope into the inner sub-query:
SELECT id, data
FROM table1 a
CROSS APPLY
(
SELECT data
FROM table2 b
CROSS APPLY (
SELECT data
FROM table3 e
WHERE a.id = e.id
) c
WHERE b.id = a.id
) d
or:
SELECT a.id, data
FROM table1 a
INNER JOIN LATERAL
(
SELECT b.id,
c.data
FROM table2 b
INNER JOIN LATERAL (
SELECT e.id,
e.data
FROM table3 e
) c
ON ( a.id = c.id )
) d
ON ( d.id = a.id )
Which, for the sample data:
CREATE TABLE table1 ( id ) AS
SELECT 1 FROM DUAL;
CREATE TABLE table2 ( id ) AS
SELECT 1 FROM DUAL;
CREATE TABLE table3 ( id, data ) AS
SELECT 1, 'A' FROM DUAL;
Both output:
ID | DATA
-: | :---
1 | A
db<>fiddle here

Related

Get column name from one table by id in another table

I have 2 tables
Table 1:
Query_code | Item_code | Column_Name
2 | 1 | CN1
2 | 2 | CN2
2 | 3 | CN3
Table 2:
Query_code | Source_item| dest_item | pair_code
2 | 1 | 2 | 1
2 | 2 | 3 | 2
What i want to achive is to get source_item-dest_item as result.
According to data that will be:
CN1-CN2
CN2-CN3
What i tried is:
SELECT A.Column_Name
FROM TABLE1 A inner join
TABLE2 B
ON A.QUERY_CODE=B.QUERY_CODE
But this is not even close to my goal
What you need to do is use TABLE2 to identify the source_item and dest_item, then join with TABLE1 the first time to replace source_item with the column name, and join again with TABLE1 to replace dest_item with the other column name.
SELECT A.Column_Name, B.Column_Name
FROM t2 C
LEFT JOIN t1 A
ON C.Source_item=A.Item_code
LEFT JOIN t1 B
ON C.Dest_item=B.Item_code
WHERE C.Query_code=A.Query_code
AND C.Query_code=B.Query_code
Running Example on SQLFiddle
This should work. It is unclear what your Query_Code is meant to do, so I omitted it from the query.
EDIT Inserted Query_code condition as well.
SELECT
Source.Column_Name || '-' || Dest.Column_Name AS ResultPair
FROM
TABLE2 B
INNER JOIN TABLE1 Source
ON B.source_item = Source.item_code AND B.Query_code = Source.Query_code
INNER JOIN TABLE1 Dest
ON B.dest_item = Dest.item_code AND B.Query_code = Dest.Query_code;
Here you go
WITH table1 (query_code, item_code ,column_name ) AS
(SELECT 2,1,'cn1' UNION ALL
SELECT 2,2,'cn2' UNION ALL
SELECT 2,3,'cn3'),
table2 (query_code , source_item, dest_item , pair_code) AS
(SELECT 2,1,2,1 UNION ALL
SELECT 2,2,3,2)
SELECT a.column_name || '-' || c.column_name
FROM table1 a
INNER JOIN table2 b ON a.item_code=b.source_item
INNER JOIN table1 c ON c.item_code=b.dest_item;

SQL SELECT multiple SUM() error

I am having a problem involving multiple SUM() functions in a SQL SELECT statement using JOINs.
Whenever I sum together two values, it makes the value inside the other sum function double. How do I prevent this?
Example: SQL Fiddle - all X and Y values should be a 2.
I am using SQLite.
You can use UNION for this:
SELECT id, SUM(bamount) AS BAmount, SUM(camount) AS CAmount
FROM
(
SELECT a.id, SUM(b.amount) AS bamount, 0 AS camount
FROM a
LEFT JOIN b ON a.id = b.a_id
GROUP BY a.id
UNION ALL
SELECT a.id, 0, SUM(c.amount) AS camount
FROM a
LEFT JOIN c ON a.id = c.a_id
GROUP BY a.id
) AS t
GROUP BY id;
updated demo
This will give you:
| id | BAmount | CAmount |
|----|---------|---------|
| 1 | 2 | 2 |
| 2 | 2 | 2 |
| 3 | 2 | 2 |
You can try performing the aggregations in separate subqueries. This is one way to get around the problem of double (or triple, etc.) counting rows as the result of a join.
SELECT
a.id,
t1.b_sum AS x,
t2.c_sum AS y
FROM a
LEFT JOIN
(
SELECT a_id, SUM(amount) AS b_sum
FROM b
GROUP BY a_id
) t1
ON a.id = t1.a_id
LEFT JOIN
(
SELECT a_id, SUM(amount) AS c_sum
FROM c
GROUP BY a_id
) t2
ON a.id = t2.a_id;

SQL Query to get missing staff member

I have following problem to find out if a User with a specific job role is missing in one project:
Table 1:
ID | Project_ID
---+------------
1 | 11A
1 | 11B
1 | 11C
2 | 12B
2 | 12C
3 | 13A
3 | 13C
Table 2:
Project_ID | JobRole_ID
-------------+------------
11A | A
11B | B
11C | C
12B | B
12C | C
13A | A
13C | C
Table 3:
JobRole_ID | JobRole
-----------+---------
A | Manager
B | Project Leader
C | Project Assistent
For each project jobrole A,B and C are required (Table 3). Table 2 only contains added JobRoles, not missing ones.
What i expect is:
ID | JobRole
---+---------
1 | Manager
2 | NULL
3 | Manager
Please help me! Thx
You want to find Projects where exists a JobRole which is not tied to this particular project.
From top of my head:
--try to find projects
SELECT
T1.Id
FROM
Table1 AS T1
WHERE
--with at least one role
EXISTS(
SELECT
*
FROM
Table3 AS T3
WHERE
--where mapping does not exist
NOT EXISTS(
SELECT
*
FROM
Table2 AS T2
WHERE
T2.Project_ID = T1.Project_ID AND
T2.JobRole_ID = T3.JobRole_ID
)
)
EDIT:
Could this be what you want? If not, could you please give us more details?
SELECT
T1.Id, T3.JobRole_ID
FROM
Table1 AS T1 LEFT JOIN
Table2 AS T2 ON T2.Project_ID = T1.Project_ID LEFT JOIN
Table3 AS T3 ON T3.JobRole_ID = T2.JobRole_ID
Based on your updated requirements this should work, although I'm sure it can be simplified.
select a.ID, b.JobRole
from (
select * from Table1, table3 where JobRole_ID = 'A'
) a left join (
select t1.id, t3.jobrole
from table1 t1
left join table2 t2 on t2.project_id = t1.project_id
left join table3 t3 on t3.jobrole_id = t2.jobrole_id
) b on a.id = b.id and a.jobrole = b.jobrole
group by a.ID, b.JobRole
Here is a method:
select p.*, j.*
from projects p cross join
jobroles j left join
projectjobs pj
on p.project_id = pj.project_id and
j.jobrole_id = pj.jobrole_id
where pj.project_id is null;
It generates a list of all projects and all jobs (using the cross join). Then, using the left join and where clause, it filters out the ones that exist.
EDIT:
You can try with comma:
select p.*, j.*
from projects p,
jobroles j left join
projectjobs pj
on p.project_id = pj.project_id and
j.jobrole_id = pj.jobrole_id
where pj.project_id is null;
But this may not work because of the semantics of how the comma is parsed in the from clause. You might need a subquery:
select xpj.*
from (select p.*, j.*
from projects p, jobroles j
) xpj left join
projectjobs pj
on xpj.project_id = pj.project_id and
xpj.jobrole_id = pj.jobrole_id
where pj.project_id is null;

Write a query to fetch data from two database

Followings are the table name.both database have same table and column name.
field_data_field_name
| Entity_id| field_name_value|
| 1 | XYZ |
field_data_field_address
-----------------------------------
| Entity_id | field_address_value|
| 1 | abc |
field_data_field_county
----------------------------------
| Entity_id | field_county_value|
| 1 | mumbai |
field_data_field_select_area
---------------------------------------
| Entity_id | field_select_area_value|
| 1 | pension |
users
------------------------------------
| uid | mail |
| 1 | sopu.phadke080#gmail.com |
In single database on basis of Entity_id=uid we join tables and data fetch successfully.
following is query for single database.
SELECT
field_data_field_name.field_name_value,
field_data_field_address.field_address_value,
field_data_field_county.field_county_value,
field_data_field_select_area.field_select_area_value,
users.mail
FROM users
INNER JOIN field_data_field_name On field_data_field_name.entity_id= uid
INNER JOIN field_data_field_address On field_data_field_address.entity_id = uid
INNER JOIN field_data_field_county On field_data_field_county.entity_id = uid
INNER JOIN field_data_field_select_area On field_data_field_select_area.entity_id = uid
I create this query but not working.please help me.
SELECT
a.field_name_value,
b.field_address_value,
c.field_county_value,
d.field_select_area_value,
e.field_name_value,
f.field_address_value,
g.field_county_value,
h.field_select_area_value
FROM
dbeng.field_data_field_name As a,
dbeng.field_data_field_address As b,
dbeng.field_data_field_county As c,
dbeng.field_data_field_select_area As d,
inner join dbspa.field_data_field_name As e ON <field_data_field_name.field_name_value>=<field_data_field_name.field_name_value>,
inner join dbspa.field_data_field_address As f ON <field_data_field_address.field_address_value>=<field_data_field_address.field_address_value>,
inner join dbspa.field_data_field_county As g ON <field_data_field_county.field_county_value>=<field_data_field_county.field_county_value>,
inner join dbspa.field_data_field_select_area As h ON <field_data_field_select_area.field_select_area_value>=<field_data_field_select_area.field_select_area_value>
WHERE d.field_select_area_value ='Pensión Compensatoria' && h.field_select_area_value ='Pensión Compensatoria' && c.field_county_value ='Alameda' && g.field_county_value='Alameda'
The concept of storing such information in two different databases does not sound right, but if you need to get data from both, you will have to do a UNION ALL:
SELECT x.col1, x.col2
FROM
(
SELECT a.col1, b.col1
FROM db1.a
JOIN db1.b ON ( ... )
UNION ALL
SELECT a.col1, b.col1
FROM db2.a
JOIN db2.b ON ( ... )
) x
WHERE x.col1 = ...
select Col1,Col2
from DB1..Tbl1
join Tbl2 on Tbl2.Col2 = DB1..Tbl1.Col1
You can access table of another database with syntax as : DatabaseName..TableName.ColumnName

Select first record in a One-to-Many relation using left join

I'm trying to join two tables using a left-join. And the result set has to include only the first record from the "right" joined table.
Lets say I have two tables A and B as below;
Table "A"
code | emp_no
101 | 12222
102 | 23333
103 | 34444
104 | 45555
105 | 56666
Table "B"
code | city | county
101 | Glen Oaks | Queens
101 | Astoria | Queens
101 | Flushing | Queens
102 | Ridgewood | Brooklyn
103 | Bayside | New York
Expected Output:
code | emp_no | city | county
101 | 12222 | Glen Oaks | Queens
102 | 23333 | Ridgewood | Brooklyn
103 | 34444 | Bayside | New York
104 | 45555 | NULL | NULL
105 | 56666 | NULL | NULL
If you notice my result has only the one matched record from table "B"(doesn't matter what record is matched) after left join (and it is a one to many mapping)
I need to pick the first matched record from table B and ignore all other rows.
Please help!
Thanks
After playing around a bit, this turns out to be trickier than I'd expected! Assuming that table_b has some single column that is unique (say, a single-field primary key), it looks like you can do this:
SELECT table_a.code,
table_a.emp_no,
table_b.city,
table_b.county
FROM table_a
LEFT
JOIN table_b
ON table_b.code = table_a.code
AND table_b.field_that_is_unique =
( SELECT TOP 1
field_that_is_unique
FROM table_b
WHERE table_b.code = table_a.code
)
;
Another option: OUTER APPLY
If supported by the database, OUTER APPLY is an efficient and terse option.
SELECT *
FROM
Table_A a
OUTER APPLY
(SELECT TOP 1 *
FROM Table_B b_1
WHERE b_1.code = a.code
) b
;
This results in a left join to the indeterminate first matched record. My tests show it to be quicker than any other posted solution (on MS SQL Server 2012).
The highest voted answer does not seem correct to me, and seems overcomplicated.
Just group by the code field on table B in your subquery and select the maximum Id per grouping.
SELECT
table_a.code,
table_a.emp_no,
table_b.city,
table_b.county
FROM
table_a
LEFT JOIN
table_b
ON table_b.code = table_a.code
AND table_b.field_that_is_unique IN
(SELECT MAX(field_that_is_unique)
FROM table_b
GROUP BY table_b.code)
If you are on SQL Server 2005 or later version, you could use ranking to achieve what you want. In particular, ROW_NUMBER() seems to suit your needs nicely:
WITH B_ranked AS (
SELECT
*,
rnk = ROW_NUMBER() OVER (PARTITION BY code ORDER BY city)
FROM B
)
SELECT
A.code,
A.emp_no,
B.city,
B.county
FROM A
LEFT JOIN B_ranked AS B ON A.code = B.code AND b.rnk = 1
OR
WITH B_unique_code AS (
select * from(
SELECT
*,
rnk = ROW_NUMBER() OVER (PARTITION BY code ORDER BY city)
FROM B
) AS s
where rnk = 1
)
SELECT
A.code,
A.emp_no,
B.city,
B.county
FROM A
LEFT JOIN B_unique_code AS B ON A.code = B.code
I modified the answer from ruakh and this seem to work perfectly with mysql.
SELECT
table_a.code,
table_a.emp_no,
table_b.city,
table_b.county
FROM table_a a
LEFT JOIN table_b b
ON b.code = a.code
AND b.id = ( SELECT id FROM table_b
WHERE table_b.code = table_a.code
LIMIT 1
)
;
this is how:
Select * From TableA a
Left Join TableB b
On b.Code = a.Code
And [Here put criteria predicate that 'defines' what the first record is]
Hey, if the city and county are unique, then use them
Select * From TableA a
Left Join TableB b
On b.Code = a.Code
And b.City + b.county =
(Select Min(city + county)
From TableB
Where Code = b.Code)
But the point is you have to put some expression in there to tell the query processor what it means to be first.
In Oracle you can do:
WITH first_b AS (SELECT code, min(rowid) AS rid FROM b GROUP BY code))
SELECT a.code, a.emp_no, b.city, b.county
FROM a
INNER JOIN first_b
ON first_b.code = a.code
INNER JOIN b
ON b.rowid = first_b.rid