Select from Many-to-Many with GroupBy - sql

I have three entities:
Cue(id, name)
Reaction(id, name)
Freqs(id, cue_id FK, reaction_id FK, some_other_data)
I want to count number of (cue, reaction) pairs like (cue.name, reaction.name, count)
I already wrote a query
SELECT
a.cue_id,
a.reaction_id,
Count(*) as freq
FROM
rdb_freqs a
JOIN rdb_reaction b ON a.cue_id=b.id
JOIN rdb_cue c ON a.reaction_id=c.id
GROUP BY a.cue_id, a.reaction_id
ORDER BY freq DESC;
But how should I replace 'id' with 'name'?

SELECT distinct
c.name cue_name,
b.name reaction_name,
(SELECT
Count(*)
FROM
rdb_freqs a1
where
a1.cue_id = a.cue_id and
a1.reaction_id = a.reaction_id
) as count
FROM
rdb_freqs a
inner JOIN rdb_reaction b ON a.reaction_id = b.id
inner JOIN rdb_cue c ON a.cue_id = c.id
order by count desc
SQLfiddle sample (written in oracle)

SELECT
c.name as cue_name,
b.name as reacion_name,
Count(*) as freq
FROM
rdb_freqs a
JOIN rdb_reaction b ON a.cue_id=b.id
JOIN rdb_cue c ON a.reaction_id=c.id
GROUP BY c.name, b.name
ORDER BY freq DESC;

SELECT
FROM rdb_freq f
INNER JOIN (
SELECT
a.cue_id,
a.reaction_id,
Count(*) as freq
FROM
rdb_freqs a
JOIN rdb_reaction b ON a.cue_id=b.id
JOIN rdb_cue c ON a.reaction_id=c.id
GROUP BY a.cue_id, a.reaction_id
) AS tot ON f.cue_id = tot.cue_id
INNER JOIN reaction

Related

SQL Select count of items from a child table with a where clause

SQL Query :
select c.cid, la.lid, b.bid, b.type
from c c
left join la la on c.cid = la.cid
left join b b on la.lid = b.lid
where b.type = 'Primary';
There are three tables c -> la -> b
I need the total count of 'b' for any given 'la' but I need to have " b.type = 'Primary' " in the where clause for other purposes.
b.type has two types - Primary and Secondary but I want a count of total number of 'b' (Primary and Secondary) Can somebody give any hints ? It would be a good learning for me. Thanks.
sample data and desired o/p
Try this:
SELECT
c.cid,
la.lid,
b.bid,
b.type,
d.cbdi
FROM c c
LEFT JOIN la la ON c.cid = la.lid
LEFT JOIN b b ON la.lid2 = b.lid2
LEFT JOIN (
SELECT
la.lid,
COUNT(b.bid) AS cbid
FROM la la
LEFT JOIN b b ON la.lid2 = b.lid2
GROUP BY la.lid
) d ON la.lid = d.lid
WHERE
b.type = 'Primary';
You can not have row having secondary in desired output as per your attached screenshot because of clause where b.type = 'Primary'. Please check again, looks like your requirement is not clear.
You seem to want to show all rows unaggregated but show an aggregation (the b count) along. This is done with a window function, COUNT OVER in your case.
select c.cid, la.lid, b.bid, b.type, count(*) over (partition by la.lid) as number_of_b
from la
join c on c.cid = la.cid
join b on b.lid = la.lid
order by c.cid, la.lid, b.bid;
If you want to restrict this to la that have at least one primary b, extend this query accordingly:
select cid, lid, bid, type, number_of_b
from
(
select
c.cid, la.lid, b.bid, b.type,
count(*) over (partition by la.lid) as number_of_b,
max(case when b.type = 'Primary' then 1 else 0 end) over (partition by la.lid)
as has_primary_b
from la
join c on c.cid = la.cid
join b on b.lid = la.lid
order by c.cid, la.lid, b.bid
)
where has_primary_b = 1;
One solution would be to join table b twice on for selecting only the Primary records and one to count all. Something like:
select c.cid, la.lid, count(bt.id)
from c c
join la la on c.cid = la.cid
join b b on la.lid = b.lid
join b bt on la.lid = bt.lid
where b.type = 'Primary'
group by c.cid, la.lid;

Count with exists in SQL

Why is this query not returning the count of the results? How do I get it to show the count
SELECT COUNT (*) AS MWith
FROM member m
JOIN Channel mc ON mc.MemberID = m.id
JOIN Client c ON c.id = m.clientid
JOIN packages p ON p.id = m.packageid
WHERE Enroll > '2018'
AND EXISTS (
SELECT * FROM
activity a
WHERE a.memberid = m.id
AND a.code IN ('785', 'a599')
)
GROUP BY m.id;
OUTPUT
MWith
1
1
1
The empty set is because of the clause group by .
The workarounds are:
Remove a GROUP BY, because m.id anyway is not part of the output
Use GROUP BY ALL
An original example:
SELECT COUNT(*) AS MWith
FROM member m
JOIN Channel mc
ON mc.MemberID = m.id
JOIN Client c
ON c.id = m.clientid
JOIN packages p
ON p.id = m.packageid
WHERE Enroll > '2018'
AND EXISTS
(
SELECT *
FROM activity a
WHERE a.memberid = m.id
AND a.code IN ( '785', 'a599' )
)
-- GROUP BY m.id;
Other, simpler examples to show a difference:
-- returns an empty resultset
SELECT COUNT(*) FROM sys.databases
WHERE 1=0
GROUP BY name
-- returns: a single row with 0
SELECT COUNT(*) FROM sys.databases
WHERE 1=0
-- Another example with GROUP BY ALL
-- it returns one row per grouped value, with expected count = 0
SELECT COUNT(*) FROM sys.databases
WHERE 1=0
GROUP BY ALL name

Referencing an aliased subquery in Oracle

I have the following query :
select
A.A_ID,
B.Lib,
A.Lib,
C.Lib,
(SELECT count(*) FROM X WHERE A.A_ID = X.A_ID) AS countX,
(SELECT count(*) FROM Y WHERE A.A_ID = Y.A_ID) AS countY,
(SELECT count(*) FROM Z WHERE A.A_ID = Z.A_ID) AS countZ
from
A
left outer join
C
on A.C_ID=C.C_ID
left outer join
B
on A.B_ID=B.B_ID
WHERE
countX = 2 AND countY = 3
ORDER BY
countZ DESC;
But this gives me the following error:
SQL Error [904] [42000]: ORA-00904: "COL_5_0_" : identificateur non
valide
How can I solve this ?
try like below, i think you missed type group by it would be order by
with cte as
(
select
A.A_ID,
B.Lib,
A.Lib,
C.Lib,
(SELECT count(*) FROM X WHERE A.A_ID = X.A_ID) AS countX,
(SELECT count(*) FROM Y WHERE A.A_ID = Y.A_ID) AS countY,
(SELECT count(*) FROM Z WHERE A.A_ID = Z.A_ID) AS countZ
from
A
left outer join
C
on A.C_ID=C.C_ID
left outer join
B
on A.B_ID=B.B_ID
) select * from cte where countX = 2 AND countY = 3
Order BY
countZ DESC

Finding the count

I have the following SQL query and need to know the count of companyid as I can see repeating data. How do I find the count of it. Following is the query
SELECT a.companyId 'companyId'
, i.orgDebtType 'orgDebtType'
, d.ratingTypeName 'ratingTypeName'
, c.currentRatingSymbol 'currentRatingSymbol'
, c.ratingStatusIndicator 'ratingStatusIndicator'
, g.qualifierValue 'qualifierValue'
, c.ratingdate 'ratingDate'
, h.value 'outlook'
FROM ciqRatingEntity a
JOIN ciqcompany com
on com.companyId = a.companyId
JOIN ciqratingobjectdetail b ON a.entitySymbolValue = b.objectSymbolValue
JOIN ciqRatingData c ON b.ratingObjectKey = c.ratingObjectKey
JOIN ciqRatingType d ON b.ratingTypeId = d.ratingTypeId
JOIN ciqRatingOrgDebtType i ON i.orgDebtTypeId=b.orgDebtTypeId
JOIN ciqRatingEntityData red ON red.entitySymbolValue=a.entitySymbolValue
AND red.ratingDataItemId='1' ---CoName
LEFT JOIN ciqRatingDataToQualifier f ON f.ratingDataId = c.ratingDataId
LEFT JOIN ciqRatingQualifiervalueType g ON g.qualifiervalueid = f.qualifierValueId
LEFT JOIN ciqRatingValueType h ON h.ratingValueId = c.outlookValueId
WHERE 1=1
AND b.ratingTypeId IN ( '130', '131', '126', '254' )
-- and a.companyId = #companyId
AND a.companyId IN
(SELECT distinct TOP 2000000
c.companyId
FROM ciqCompany c
inner join ciqCompanyStatusType cst on cst.companystatustypeid = c.companystatustypeid
inner join ciqCompanyType ct on ct.companyTypeId = c.companyTypeId
inner join refReportingTemplateType rep on rep.templateTypeId = c.reportingtemplateTypeId
inner join refCountryGeo rcg on c.countryId = rcg.countryId
inner join refState rs on rs.stateId = c.stateId
inner join ciqSimpleIndustry sc on sc.simpleIndustryId = c.simpleIndustryId
ORDER BY companyid desc)
ORDER BY companyId DESC, c.ratingdate, b.ratingTypeId, c.ratingStatusIndicator
This will list where there are duplicate companyID's
SELECT companyId, count(*) as Recs
FROM ciqCompany
GROUP BY ciqCompany
HAVING count(*) > 1
I understand that you wish to add a column to the query with the count of each companyId, you can use COUNT() OVER():
select count(a.companyId) over (partition by a.companyId) as companyCount,
<rest of the columns>
from ciqRatingEntity a
join <rest of the query>
This would return in each row the count of the companyId of that row without grouping the results.

Join Using Maximum Date

I have a table that I am trying to join with based on an ID, however I only want to join with the rows that have the maximum "PeriodDT" (a datetime column) for that ID.
I have tried using the Top 1 order by that "PeriodDT" however it will only let me select one column or I get the error:
Only one expression can be specified in the select list when the
subquery is not introduced with EXISTS
Here is the query I Used:
Select a.Name as PropertyName,
a.PropertyNum as PropertyNum,
a.City as City,
a.State as State,
b.Name as LoanName,
b.LoanNum,
(select Top 1 c.IntRate as IntRate,
c.MaturityDT
from vNoteDetail c where c.LoanID = b.LoanID Order By c.PeriodDT DESC)
from vProperty a join vLoan b on a.LoanID = b.LoanId
Is there a better way to do this?
Try
Select a.Name as PropertyName,
a.PropertyNum as PropertyNum,
a.City as City,
a.State as State,
b.Name as LoanName,
b.LoanNum,
v1.IntRate,
v1.MaturityDT
from vProperty a join vLoan b on a.LoanID = b.LoanId
CROSS APPLY (select Top 1 c.IntRate as IntRate,
c.MaturityDT
from vNoteDetail c where c.LoanID = b.LoanID Order By c.PeriodDT DESC) AS V1
try this..
;WITH cte
AS (SELECT Row_number() OVER(partition BY clientid ORDER BY perioddt DESC) rn,
intrate,
perioddt MaturityDT,
loanid
FROM vnotedetail)
SELECT a.NAME AS PropertyName,
a.propertynum AS PropertyNum,
a.city AS City,
a.state AS State,
b.NAME AS LoanName,
b.loannum,
c.intrate,
c.maturitydt,
FROM vproperty a
JOIN vloan b
ON a.loanid = b.loanid
JOIN cte c
ON c.loanid = b.loanid
WHERE c.rn = 1
FYI restrictions of subquery CHECK THIS