Equivalent SQL Query using Cartesian Product Only - sql

given 3 tables a : {id, name_eng}, b: {id, name_spa} and c: {id, name_ita}
which is the equivalent "product cartesian query" for this given one:
select
a.name_eng
b.name_spa
c.name_ita
from
a inner join b on a.id = b.id
left outer join c on a.id = c.id

I don't know what you want, a cartesian product would be this:
SELECT a.name_eng
b.name_spa
c.name_ita
FROM a
CROSS JOIN b
CROSS JOIN c
Or the implicit way:
SELECT a.name_eng
b.name_spa
c.name_ita
FROM a,b,c
If you want your previous query written with cartesian products (why??), then this should do (on SQL Server 2000):
SELECT a.name_eng
b.name_spa
c.name_ita
FROM a,b,c
WHERE a.id = b.id
AND a.id *= c.id
If I wasn't clear enough with the "why??", you shouldn't use implicit joins since hey are deprecated, you should always use proper explicit joins.

Related

How to join tables using CASE WHEN in postgresql?

I have a PostgreSQL query like below and I want to join a new table to that when rateid>100
CASE WHEN rateid<100 Then
Select * FROM rate as A, plan AS B, room AS C
WHERE A.id=B.rateid
AND B.roomid=C.id
ELSE
Select * FROM rate as A, plan AS B, room AS C, hotel AS D
WHERE A.id=B.rateid
AND B.roomid=C.id
AND C.hotelid=D.id
END
Can I know is there any way to join hotel table when rateid>100?
In your question you say "when rateid>100", I assume you mean "rateid>=100" because in the code you use "rateid<100"
I also changed the old-style to new-style joins.
The on-clause tells SQL what to join, so adding "rateid>=100" should solve the problem (When I understand your question correctly)
select
*
from
rate as A,
inner join plan as B on
A.id = B.rateid
inner join room as C on
B.roomid = C.id
and rateid >= 100

How to rewrite SQL query without IN clause

Schema:
Table A: AID(PK), RECEIVE_DATE
Table B: BID(PK), AID(FK), MESSAGE, ITEMID, ITEMTYPE
Tables A-to-B have a one-to-many mapping.
Here is a working SQL query (in SQL Server) to find out the latest message grouped by ITEMID i.e for different ITEMID (of ITEMTYPE say as 'XYZ').
SELECT
b.MESSAGE, b.ITEMID
from a
inner join b on b.aid = a.aid AND b.ITEMTYPE = 'XYZ'
where a.receive_date in (select max(receive_date)
from a a1
inner join b b1 on b1.aid = a1.aid
where b1.itemid = b.itemid
);
How can we rewrite this SQL query without IN clause [also without rownumber concept in use], as ORACLE is having restriction for IN clause. Getting java.sql.SQLSyntaxErrorException: ORA-01795: maximum number of expressions in a list is 1000 for above expression.
It isn't clear to me why you are getting ORA-01795. Your subquery only selects a max value, which should be a single value. In addition, the 1000 value limit only applies to a list of literals, not a subquery. In any case, you could rephrase this query using a join instead of WHERE IN:
SELECT
b.MESSAGE,
b.ITEMID
FROM a
INNER JOIN b
ON b.aid = a.aid AND b.ITEMTYPE = 'XYZ'
INNER JOIN
(
SELECT
b1.itemid,
MAX(receive_date) AS max_receive_date
FROM a a1
INNER JOIN b b1
ON b1.aid = a1.aid
GROUP BY b1.itemid
) t
ON b.itemid = t.itemid
WHERE a.receive_date = t.max_receive_date
EXISTS and IN tend to be interchangeable, and EXISTS performs better in some engines (not sure about Oracle) due to the fact that it returns true on the first match, rather than generating a subset and checking against that. I'm not familiar with Oracle, but I imagine you could use the following to circumvent your 1000 row limit on IN:
SELECT
b.MESSAGE, b.ITEMID
from a
inner join b on b.aid = a.aid AND b.ITEMTYPE = 'XYZ'
where exists (
SELECT 1
from a a1
inner join b b1 on b1.aid = a1.aid
where b1.itemid = b.itemid
having MAX(a1.receive_date) = a.receive_date
)

Same ID field on multiple tables

So I've been given a task where i should present the following:
ID, LNAME, FNAME, MNAME, BIRTH_DATE, RELG_CODE, NAT_CODE, PT_STATUS, RM_NO, DTTM_ADM
The tables are:
HISR_CODES, PASR_NAMES, PASR_PROFILE, PAST_PATIENT_ADM
--Viewing them using DESC--
So while I viewed them, I was told that the ID on these tables are the same. So what I did so far in the coding (I'll finish the rest but I need to make sure this works first):
SELECT
A.ID,
A.LNAME,
A.FNAME,
A.MNAME,
A.BIRTH_DATE,
C.RELG_CODE,
C.NAT_CODE,
B.PT_STATUS,
B.RM_NO,
B.DTTM_ADM
FROM
PASR_NAMES A,
PASR_PROFILE B,
PAST_PATIENT_ADM C,
HISR_CODES D
WHERE
A.ID = B.ID
AND
B.ID = C.ID
AND
C.ID = D.ID
Is there a way to tell that all of the ID's from the tables are the same? A simpler code than going on like this:
WHERE
A.ID = B.ID
AND
B.ID = C.ID
AND
C.ID = D.ID
Or is JOIN - ON the only option for this?
You can use NATURAL JOIN as below:
SELECT
A.ID,
A.LNAME,
A.FNAME,
A.MNAME,
A.BIRTH_DATE,
C.RELG_CODE,
C.NAT_CODE,
B.PT_STATUS,
B.RM_NO,
B.DTTM_ADM
FROM
PASR_NAMES A
NATURAL JOIN PASR_PROFILE B
NATURAL JOIN PAST_PATIENT_ADM C
NATURAL JOIN HISR_CODES D;
From Oracle Reference, "A natural join is based on all columns in the two tables that have the same name." So, there is a chance that the joins happen based on other columns as well. Therefore, it is recommended that you still use the INNER JOIN syntax and explicitly specify the JOIN columns.
References:
NATURAL JOIN on Oracle® Database SQL Language Reference
Related SO question
Use the proper join syntax:
FROM PASR_NAMES A JOIN
PASR_PROFILE B
ON A.ID = B.ID JOIN
PAST_PATIENT_ADM C
ON B.ID = C.ID JOIn
HISR_CODES D
ON C.ID = D.ID
Or:
FROM PASR_NAMES A JOIN
PASR_PROFILE B
USING (ID) JOIN
PAST_PATIENT_ADM C
USING (ID)
HISR_CODES D
USING (ID)
I would discourage you from using the natural join. It might seem like the right thing at first. However, the semantics of the query are highly dependent on the structure of the tables. If columns are renamed, removed, or added, the query might still work but produce highly unexpected results.

SQL SELECT and SUM from three

I have been cracking my head for hours on what I thought to be simple SQL SELECT command. I searched every where and read all questions related to mine. I tried an SQL Command Builder, and even read and applied complete series of SQL tutorials and manuals to try to build it from scratch understanding it (which is very important for me, regarding next commands I'll eventually have to build...).
But now I'm just stuck with the results I want, but on separates SELECT commands which I seem to be unable to get together !
Here is my case : 3 tables, first linked to the second with a common id, second linked to the third with another common id, but no common id from the first to the third. Let's say :
Table A : id, name
Table B : id, idA, amount
Table C : id, idB, amount
Several names in Table A. Several amounts in Table B. Several amounts in Table C. Result wanted : each A.id and A.name, with the corresponding SUM of B.amount, and with the corresponding SUM of C.amount. Let's say :
A.id
A.name
SUM(B.amount) WHERE B.idA = A.id
SUM(C.amount) WHERE C.idB = B.id for each B which B.idA = A.id
It's okay for "the first three columns", and "the first two columns and the fourth", both with a WHERE clause and/or a LEFT JOIN. But I can't achieve cumulating all fourth columns together without messing everything !
One could say "it's easy, just put an idA column in Table C" ! Should be easier, sure. But is it really necessary ? I don't think so, but I could be wrong ! So, I just please anyone (who I will give an eternal "SQL God" decoration) with SQL skills to answer laughing "That's so simple ! Just do that and you are gone ! Stupid little newbies..." ;)
Running VB 2010 and MS SQL Server
Thanks for reading !
Try this:
SELECT A.Id, A.Name, ISNULL(SUM(B.amount), 0) as bSum, ISNULL(SUM(C2.Amount), 0) as cSum
FROM A
LEFT OUTER JOIN B ON A.Id = B.idA
LEFT OUTER JOIN (SELECT C.idB, SUM(C.AMOUNT) AS Amount FROM C GROUP BY C.idB) AS C2 ON C2.idB = B.Id
GROUP BY A.Id, A.Name
Try this:
SELECT
a.id,
a.name,
sum(x.amount) as amountb,
sum(x.amountc) as amountc
from a
left join (
select
b.id,
b.ida,
b.amount,
SUM(c.amount) as amountc
from b
left join c
on b.id = c.idb
group by
b.id,
b.amount,
b.ida
) x
on a.id = x.ida
group by
a.id,
a.name
This should give you the result set you're looking for. It sums all C.Amount's for each B.id, then adds it all together into a single result set. I tested it with a bit of sample data in MSSQL, and it works as expected.
Select a.id, a.name, sum(b.amount), sum(c.amount)
from a inner join b on a.id = b.idA
inner join c on b.id = c.idB
group by a.id, a.name
You need to add them separately:
select a.id, a.name, (coalesce(b.amount, 0.0) + coalesce(c.amount, 0.0))
from a left outer join
(select b.ida, sum(amount) as amount
from b
group by b.ida
) b
on a.id = b.ida left outer join
(select b.ida, sum(amount) as amount
from c join
b
on c.idb = b.id
group by b.ida
) c
on a.id = c.ida
The outer joins are to take into account when b and c records don't both exist for a given id.

SQL joining three tables, join precedence

I have three tables: R, S and P.
Table R Joins with S through a foreign key; there should be at least one record in S, so I can JOIN:
SELECT
*
FROM
R
JOIN S ON (S.id = R.fks)
If there's no record in S then I get no rows, that's fine.
Then table S joins with P, where records is P may or may not be present and joined with S.
So I do
SELECT
*
FROM
R
JOIN S ON (S.id = R.fks)
LEFT JOIN P ON (P.id = S.fkp)
What if I wanted the second JOIN to be tied to S not to R, like if I could use parentheses:
SELECT
*
FROM
R
JOIN (S ON (S.id = R.fks) JOIN P ON (P.id = S.fkp))
Or is that already a natural behaviour of the cartesian product between R, S and P?
All kinds of outer and normal joins are in the same precedence class and operators take effect left-to-right at a given nesting level of the query. You can put the join expression on the right side in parentheses to cause it to take effect first. Remember that you will have to move the ON clauses around so that they stay with their joins—the join in parentheses takes its ON clause with it into the parentheses, so it now comes textually before the other ON clause which will be after the parentheses in the outer join statement.
(PostgreSQL example)
In
SELECT * FROM a LEFT JOIN b ON (a.id = b.id) JOIN c ON (b.ref = c.id);
the a-b join takes effect first, but we can force the b-c join to take effect first by putting it in parentheses, which looks like:
SELECT * FROM a LEFT JOIN (b JOIN c ON (b.ref = c.id)) ON (a.id = b.id);
Often you can express the same thing without extra parentheses by moving the joins around and changing the direction of the outer joins, e.g.
SELECT * FROM b JOIN c ON (b.ref = c.id) RIGHT JOIN a ON (a.id = b.id);
When you join the third table, your first query
SELECT
*
FROM
R
JOIN S ON (S.id = R.fks)
is like a derived table to which you're joining the third table. So if R JOIN S produces no rows, then joining P will never yield any rows (because you're trying to join to an empty table).
So, if you're looking for precedence rules then in this case it's just set by using LEFT JOIN as opposed to JOIN.
However, I may be misunderstanding your question, because if I were writing the query, I would swap S and R around. eg.
SELECT
*
FROM
S
JOIN R ON (S.id = R.fks)
The second join is tied to S as you explicity state JOIN P ON (P.id = S.fkp) - no column from R is referenced in the join.
with a as (select 1 as test union select 2)
select * from a left join
a as b on a.test=b.test and b.test=1 inner join
a as c on b.test=c.test
go
with a as (select 1 as test union select 2)
select * from a inner join
a as b on a.test=b.test right join
a as c on b.test=c.test and b.test=1
Ideally, we would hope that the above two queries are the same. However, they are not - so anybody that says a right join can be replaced with a left join in all cases is wrong. Only by using the right join can we get the required result.