Is there any alternative way for following query in oracle - sql

select
a.id,
a.name,
b.group,
a.accountno,
(
select ci.cardno
from taccount ac, tcardinfo ci
where ac.accountno = ci.accountno
) as card_no
from tstudent a, tgroup b
where a.id = b.id
And how to select more than one field from (select ci.cardno from taccount ac,tcardinfo ci where ac.accountno = ci.accountno) or any others way
Please note that the is not a relation in two queries (main and subquery). Sub-query value depends on the data of the main query. Main query is set of data by joining multiple table and sub-query is also a set of data by joining multiple table

In essence, you are describing a lateral join. This is available in oracle since version 12.
Your query is rather unclear about from which table each column comes from (I made assumptions, that you might need to review), and you seem to be missing a join condition in the subquery (I added question marks in that spot)... But the idea is:
select
s.id,
s.name,
g.group,
s.accountno,
x.*
from tstudent s
inner join tgroup g on g.id = s.id
outer apply (
select ci.cardno
from taccount ac
inner join tcardinfo ci on ????
where ac.accountno = s.accountno
) x
You can then return more columns to the subquery, and then will show up in the resultset.

Related

How is my SQL subquery evaluating to more than one row? When run independently, it works fine, but doesn't work in a SELECT subquery

I am obtaining values from two tables. When I run the subquery in its own PROC SQL statement in SAS, it runs fine, with the count of citations for each ID. When I input the subquery into my SELECT outer query, it gives me ERROR: Subquery evaluated to more than one row. I am having a hard time determining the cause of this issue.
The subquery should result in one row of count of citations per ID. I am trying to get the count of citations (per ID) into my outer query. Not all items from B will be in A (hence the left join on B).
SELECT
A.AREA
,A.NAME
,B.ID
,(
SELECT
COUNT(B.TYPE)
FROM
EVAL.CITATIONS AS B
GROUP BY
B.ID
)
AS COUNT_CITATIONS
FROM
EVAL.OCT AS A
LEFT JOIN EVAL.CITATIONS
ON A.DBA = B.NAME
ORDER BY A.NAME ASC
;
I expected the outer query to pull the counts for the citations per ID. The citations are coming from table B (which I'm using to left join into table A). I have been searching forums for this error and I understand that my query is resulting in more than one row, but I can't figure out why the outer query is not simply pulling the counts I need from ID when the left join completes.
I also tried adding in the subquery this WHERE clause after researching some similar questions to no avail.
WHERE FACID = CDPH_CITATIONS.FACID
You need to use a correlated subquery where your subquery references your main query e.g.
SELECT
A.AREA
,A.NAME
,B.ID
,(
SELECT
COUNT(C.TYPE)
FROM
EVAL.CITATIONS AS C
WHERE B.ID = C.ID
GROUP BY
C.ID
)
AS COUNT_CITATIONS
FROM
EVAL.OCT AS A
LEFT JOIN EVAL.CITATIONS
ON A.DBA = B.NAME
ORDER BY A.NAME ASC
However, I don’t think you need a subquery at all, you can just count the B records and group by the other columns in your main query
Your query fails because the subquery in the SELECT clause returns more than one row: it returns the count of each and every id in the citations table, while you want just the count of the "current" id. There is also a problem with the scoping of the table identifiers (eg: B is defined in the subquery but used in the outer query).
To avoid that, we can correlate the subquery with the outer query (and fix the table aliases):
SELECT o.AREA, o.NAME, c.ID,
(SELECT COUNT(c.TYPE) FROM EVAL.CITATIONS WHERE c1.ID = c.ID) AS COUNT_CITATIONS
FROM EVAL.OCT AS o
LEFT JOIN EVAL.CITATIONS AS c ON c.NAME = o.DBA
ORDER BY o.NAME ASC
Now this can be further optimized using window functions; we do nott need to reopen the citations table in a subquery, we can perform a window count instead; this is much more efficient since the table is scanned only once. So:
SELECT o.AREA, o.NAME, c.ID,
COUNT(c.TYPE) OVER(PARTITION BY c.ID) AS COUNT_CITATIONS
FROM EVAL.OCT AS o
LEFT JOIN EVAL.CITATIONS AS c ON o.DBA = c.NAME
ORDER BY o.NAME ASC
You are getting multiple values because you did not tell it to only run the subquery for the single value of ID that matched value on the current observation of the outer query.
But in SAS there is no need to get so tricky. SAS will happily re-merge the aggregate values back onto all observations that share the group by variable values.
proc sql;
SELECT
A.NAME
,A.AREA
,B.ID
,COUNT(B.TYPE) AS COUNT_CITATIONS
FROM EVAL.OCT AS A
LEFT JOIN EVAL.CITATIONS B
ON A.DBA = B.NAME
GROUP BY ID
ORDER BY NAME
;
quit;

Returning count using multiple subqueries

Forgive my ignorance, but sql-server is not my strong suit. I'm trying to retrieve the count of rows from two mapping tables using subqueries (correlated subqueries?). If I remove one subquery, things work fine, but if I include both subqueries, I'm not getting the expected number of rows back.
SELECT
a.id,
a.name,
al_1.locationid as LocationCount,
af_1.FuncAreaId as FuncAreaCount
FROM
application as a inner join
applicationlocation as al_1 on a.id = al_1.appid inner join
applicationfuncarea as af_1 on a.id = af_1.AppId
WHERE
al_1.locationid in
(
SELECT count(locationid)
FROM applicationlocation as al_2
WHERE al_2.appid = al_1.appid
)
AND
af_1.funcareaid in
(
SELECT count(funcareaid)
FROM applicationfuncarea as af_2
WHERE af_2.appid = af_1.appid
)
If I'm not mistaken about what you want to achieve here, then this can be achieved by using grouping with COUNT and DISTINCT operators:
SELECT
a.id,
a.name,
COUNT(DISTINCT al_1.locationid) as LocationCount,
COUNT(DISTINCT af_1.FuncAreaId) as FuncAreaCount
FROM
application as a inner join
applicationlocation as al_1 on a.id = al_1.appid inner join
applicationfuncarea as af_1 on a.id = af_1.AppId
GROUP BY a.id, a.name
It is hard to tell if result is correct without seeing your data and expected result. If the above does not work, try removing DISTINCT operators and see if you get the results that you need.

Error in query: aggregate function or the GROUP BY clause

Hi all I have a problem with an SQL query: the problem is that if i add GROUP BY the database engine outputs the error:
Column 'dbo.classes.class_name' is invalid in the select list because
it is not contained in either an aggregate function or the GROUP BY clause.
My query is:
string query = "SELECT p.*
FROM dbo.classes AS p INNER JOIN teacher_classes AS a
ON a.class_id = p.class_id
and teach_id = #id
GROUP BY p.class_id";
Is there any help please for that.
Note without group by the query work fine but the result not grouped.
Your query is:
SELECT p.*
FROM dbo.classes AS p INNER JOIN
teacher_classes AS a
ON a.class_id = p.class_id and teach_id = #id
GROUP BY p.class_name;
You are trying to select all the columns from p and yet you're are grouping by class_name. This is not allowed in most databases. What happens if you have two classes, but information is different from them?
One option is to use distinct rather than group by to remove duplicates:
SELECT distinct c.*
FROM dbo.classes c INNER JOIN
teacher_classes tc
ON tc.class_id = c.class_id and tc.teach_id = #id;
Another option is to use something like in to find the matching classes for the teacher:
select c.*
from classes c
where c.class_id in (select tc.class_id from teacher_classes where teach_id = #id)
Notice I also changed your aliases so they have some relationship to the table names. This makes the query much easier to read.

Left outer join and group by issue

I wrote a query. this query sum fields from 2 different table. And grouped by main table id field. But second left outer join is not grouped and giving me different results.
SELECT s.*,
f.firma_adi,
sum(sd.fiyat) AS konak,
sum(ss.fiyat) AS sponsor
FROM fuar_sozlesme1 s
INNER JOIN fuar_firma_2012 f
ON ( s.cari = f.cari )
LEFT OUTER JOIN fuar_sozlesme1_detay sd
ON ( sd.sozlesme_id = s.id )
LEFT OUTER JOIN fuar_sozlesme1_sponsor ss
ON ( ss.sozlesme_id = s.id )
GROUP BY s.id
ORDER BY s.id DESC
I know, it is really complicated but I'm stucking on this issue.
My question is: why second left outer join is not correctly sum of field . If I remove second left outer join or first, everything is normal.
The problem is that you have multiple dimensions on your data, and the number of rows is multiplying beyond what you expect. I would suggest that you run the query for one id, without the group by, to see what rows the join is producing.
One way to fix this is by using correlated subqueries:
select s.*, f.firma_adi,
(select SUM(sd.fiyat)
from fuar_sozlesme1_detay fd
where sd.sozlesme_id = s.id
) as konak,
(select SUM(ss.fiyat)
from fuar_sozlesme1_sponsor ss
where (ss.sozlesme_id = s.id)
) as sponsor
from fuar_sozlesme1 s inner join
fuar_firma_2012 f
on (s.cari = f.cari)
order by s.id DESC
By the way, you appear to by using MySQL (because your query is not parsable in any other dialect). You should tag your questions with the version of the database you are using.

Complex join with nested group-by/having clause?

I ultimately need a list of "import" records that include "album"
records which only have one "song" each.
This is what I'm using now:
select i.id, i.created_at
from imports i
where i.id in (
select a.import_id
from albums a inner join songs s on a.id = s.album_id
group by a.id having 1 = count(s.id)
);
The nested select (with the join) is blazing fast, but the external
"in" clause is excruciatingly slow.
I tried to make the entire query a single (no nesting) join but ran
into problems with the group/having clauses. The best I could do was
a list of "import" records with dupes, which is not acceptable.
Is there a more elegant way to compose this query?
How's this?
SELECT i.id,
i.created_at
FROM imports i
INNER JOIN (SELECT a.import_id
FROM albums a
INNER JOIN songs s
ON a.id = s.album_id
GROUP BY a.id
HAVING Count(* ) = 1) AS TEMP
ON i.id = TEMP.import_id;
In most database systems, the JOIN works a lost faster than doing a WHERE ... IN.
SELECT i.id, i.created_at, COUNT(s.album_id)
FROM imports AS i
INNER JOIN albums AS a
ON i.id = a.import_id
INNER JOIN songs AS s
ON a.id = s.album_id
GROUP BY i.id, i.created_at
HAVING COUNT(s.album_id) = 1
(You might not need to include the COUNT in the SELECT list itself. SQL Server doesn't require it, but it's possible that a different RDBMS might.)
Untested:
select
i.id, i.created_at
from
imports i
where
exists (select *
from
albums a
join
songs s on a.id = s.album_id
where
a.import_id = i.id
group by
a.id
having
count(*) = 1)
OR
select
i.id, i.created_at
from
imports i
where
exists (select *
from
albums a
join
songs s on a.id = s.album_id
group by
a.import_id, a.id
having
count(*) = 1 AND a.import_id = i.id)
All three sugested techniques should be faster than your WHERE IN:
Exists with a related subquery (gbn)
Subquery that is inner joined (achinda99)
Inner Joining all three tables (luke)
(All should work, too ..., so +1 for all of them. Please let us know if one of them does not work!)
Which one actually turns out to be the fastest, depends on your data and the execution plan. But an interesting example of different ways for expressing the same thing in SQL.
I tried to make the entire query a
single (no nesting) join but ran into
problems with the group/having
clauses.
You can join subquery using CTE (Common Table Expression) if you are using SQL Server version 2005/2008
As far as I know, CTE is simply an expression that works like a virtual view that works only one a single select statement - So you will be able to do the following.
I usually find using CTE to improve query performance as well.
with AlbumSongs as (
select a.import_id
from albums a inner join songs s on a.id = s.album_id
group by a.id
having 1 = count(s.id)
)
select i.id, i.created_at
from imports i
inner join AlbumSongs A on A.import_id = i.import_id