Unexpected answer from query with sub-selects - sql

When I execute this query then all departs shown in depart_decode column and there figures also =Nil
select D.depart_decode
(select count (Staff_NO) from AA.table where Depart_code=D.Depart_code and Depart_code=151 and Staff_Sub_NO=5) Manager,
(select count (Staff_NO) from AA.table where Depart_code=D.Depart_code and Depart_code=151 and Staff_Sub_NO=4) HOD,
(select count (Staff_NO) from AA.table where Depart_code=D.Depart_code and Depart_code=151 and Staff_Sub_NO=3) Head,
(select count (Staff_NO) from AA.table where Depart_code=D.Depart_code and Depart_code=151 and Staff_Sub_NO in(1,2)) staff
from AA.Departments D

You query contains this where clause in each subselect:
where Depart_code=D.Depart_code and Depart_code=151
This evaluates to true only, if a Depart_code 151 exists in table Departments and only for that row.
Remove and Depart_code=151and you should get your results.

Using correlated subqueries in a select clause is often a source of performance problems. I would recommend using a subquery to prepare the counts you want and just join that back to the department table.
SELECT
D.depart_decode, c.Manager, c.Hod, c.Head, c.staff
FROM AA.Departments D
INNER JOIN (
SELECT
Depart_code
, COUNT(CASE WHEN Staff_Sub_NO = 5 THEN Staff_NO END) Manager
, COUNT(CASE WHEN Staff_Sub_NO = 4 THEN Staff_NO END) HOD
, COUNT(CASE WHEN Staff_Sub_NO = 3 THEN Staff_NO END) Head
, COUNT(CASE WHEN Staff_Sub_NO < 3 THEN Staff_NO END) staff
FROM AA.table
GROUP BY
Depart_code
) C ON D.Depart_code = C.Depart_code
;

Related

Getting undesired output in SQL Server while using pivot

I am looking for an output of:
but getting this instead:
The two tables which I have used are Table 1 and Table 2.
I am providing the links for the table as well Kaggle Dataset
The code I have
SELECT *
FROM
(SELECT
nr.region, Medal,
COUNT(Medal) AS 'Total_Medal'
FROM
athlete_events AS ae
JOIN
noc_regions AS nr ON ae.NOC = nr.NOC
WHERE
Medal <> 'NA'
GROUP BY
Medal, nr.region) AS t1
PIVOT
(COUNT(Medal)
FOR Medal IN ([Gold], [Silver], [Bronze])
) pivot_table
ORDER BY
Total_Medal DESC
Please help me to solve this, consider me a novice
Try This, you will get exact output
Select OH.Region,
Count(Case When O.Medal='Gold' Then 1 End) AS Gold,
Count(Case When O.Medal='Silver' Then 1 End) AS Silver,
Count(Case When O.Medal='Bronze' Then 1 End) AS Bronze
from athlete_events O
Join noc_regions OH On OH.NOC = O.NOC
Group by OH.Region
Order By Gold Desc,Silver Desc,Bronze Desc
I think you probably just want something like:
SELECT *
FROM (
SELECT nr.region, medal
FROM athlete_events ae INNER JOIN noc_regions nr
ON ae.noc = nr.noc
WHERE medal <> 'NA'
) t1
PIVOT(COUNT(medal) FOR medal in ([Gold], [Silver], [Bronze])) pt
ORDER BY gold+silver+bronze DESC
There doesn't appear to be any reason for your inner grouping and counting. The pivot can handle the count and, since you don't want total medal in your output (except for the order), you can just sum the medal fields in the ORDER BY.
So I kinda gave up on pivot myself. Caused me to many problems in the past (always my own mistakes ofcourse) and when I can I try a different approache.
So I'll show you a query that tells you how you can get the results you want, but it won't answer your pivot question. This method isn't the most efficient, but it's fine for a size of these records and I think it makes the query even more readable.
SELECT
region
, SUM(Gold) AS 'Gold'
, SUM(Silver) AS 'Silver'
, SUM(Bronze) AS 'Bronze'
FROM
noc_regions
LEFT JOIN (SELECT NOC, COUNT(*) AS 'Gold' FROM athlete_events WHERE Medal = 'Gold' GROUP BY NOC) gold_events ON noc_regions.NOC = gold_events.NOC
LEFT JOIN (SELECT NOC, COUNT(*) AS 'Silver' FROM athlete_events WHERE Medal = 'Silver' GROUP BY NOC) silver_events ON noc_regions.NOC = silver_events.NOC
LEFT JOIN (SELECT NOC, COUNT(*) AS 'Bronze' FROM athlete_events WHERE Medal = 'Bronze' GROUP BY NOC) bronze_events ON noc_regions.NOC = bronze_events.NOC
GROUP BY
region
ORDER BY
Gold DESC
, Silver DESC
, Bronze DESC
, region ASC;

how to select in select postgresql

I have a column named jenis_kelamin I want to display the gender of male and female in a select query. I have a query like this but the data that comes out is still wrong, what is the correct way?
SELECT distinct mj.id, mj.nama_pd,
(select distinct count(jenis_layanan) from public.isian_kuis
where jenis_kelamin = 'Laki' ) as jumlah_laki,
(select distinct count(jenis_layanan)
from public.isian_kuis
where jenis_kelamin = 'Perempuan' ) as jumlah_perempuan
FROM public.master_jabatan mj
join isian_kuis ik on ik.jabatan_id = mj.id
group by mj.id,mj.nama_pd
order by mj.id;
I have an example of the image of my query, this is still wrong
The correct data is that at ID 30 it has two men and one woman, in ID 29 there is only one woman
No need to use nested select just use Group By like this:
SELECT distinct mj.id,
mj.nama_pd,
SUM(CASE WHEN jenis_kelamin = 'Laki' THEN 1 ELSE 0 end) AS jumlah_laki,
SUM(CASE WHEN jenis_kelamin = 'Perempuan' THEN 1 ELSE 0 end) AS jumlah_perempuan
FROM public.master_jabatan mj
join isian_kuis ik on ik.jabatan_id = mj.id
group by mj.id,mj.nama_pd
order by mj.id;
In Postgres, you can use conditional aggregation which looks like:
SELECT mj.id, mj.nama_pd,
COUNT(*) FILTER (WHERE jenis_kelamin = 'Laki')AS jumlah_laki,
COUNT(*) FILTER (WHERE jenis_kelamin = 'Perempuan') AS jumlah_perempuan
FROM public.master_jabatan mj JOIN
isian_kuis ik
ON ik.jabatan_id = mj.id
GROUP BY mj.id, mj.nama_pd
ORDER BY mj.id;
Note that it is very, very rare to use SELECT DISTINCT with GROUP BY. This might slow down the query. And FILTER is standard SQL so is a good way to implement this.

Aggregate Function on an Expression Containing A Subquery

With the following t-sql query:
select u.userid
into #temp
from user u
where u.type = 1;
select top 50
contentid,
count(*) as all_views,
sum(case when hc.userid in (select userid from #temp) then 1 else 0 end) as first_count,
sum(case when hc.userid in (40615, 40616) then 1 else 0 end) as another_count
from hitcounts hc
inner join user u on u.userid = hc.userid
group by hc.contentid
order by count(*) desc;
I get an error message
Cannot perform an aggregate function on an expression containing an aggregate or a subquery.
However, if just include the column 'another_count' (with the hard-coded list of identifiers), everything works as I expected. Is there a way I should go about only getting the count for userids contained within a subquery? I plan to have multiple columns, each counting up a set/subquery of different userids.
Performance is not a concern at this point and I appreciate any guidance.
You don't need a temporary table for this purpose. Just use a conditional aggregation:
select top 50 contentid,
count(*) as all_views,
sum(case when u.type = 1 then 1 else 0 end) as first_count,
sum(case when hc.userid in (40615, 40616) then 1 else 0 end) as another_count
from hitcounts hc join
user u
on u.userid = hc.userid
group by hc.contentid
order by count(*) desc;

aliasing pivot column

i am trying to alias the pivot column to scenario1, scenario2, scenario3 instead of 1,2,3. I am getting error.
select *
from (select *
from (select s.campaign_id campaign_id, s.scenario_index scenario_index
from scenario s, campaign c where s.campaign_id = c.campaign_id)
pivot (max(scenario_index)for scenario_index in (1,2,3))
)a
thank you, aggregation gives the result with alias now. The requirement i have is to combine these columns with another query which is
select CASE WHEN AWARD_TYPE = 0 THEN award_rate||' points'
when AWARD_TYPE = 1 then Award_rate||' %'
when award_type=2 then RATIO_POINTS||' points per '||RATIO_MON_UNIT||' AED' End
from points_rule p
where c.pt_basic_rule_id = p.point_rule_id ) as pool_awards,
this query comes as a column and then the scenario1, 2,3 should come as 3 columns with the value of the pool_award based on the campaign_id
Just use conditional aggregation:
select s.campaign_id,
max(case when scenario_index = 1 then 1 end) as scenario1,
max(case when scenario_index = 2 then 1 end) as scenario2,
max(case when scenario_index = 3 then 1 end) as scenario3
from scenario s join
campaign c
on s.campaign_id = c.campaign_id
group by campaign_id;
You can use an alias in IN clause of the PIVOT as follows:
select *
from (select *
from (select s.campaign_id campaign_id, s.scenario_index scenario_index
from scenario s, campaign c where s.campaign_id = c.campaign_id)
pivot (max(scenario_index)for scenario_index in (1 as scenario1,2 as scenario2,3 as scenario3))
)a

SQL Aggreate Functions

I have table which list a number of cases and assigned primary and secondary technicians. What I am trying to accomplish is to aggregate the number of cases a technician has worked as a primary and secondary tech. Should look something like this...
Technician Primary Secondary
John 4 3
Stacy 3 1
Michael 5 3
The table that I am pulling that data from looks like this:
CaseID, PrimaryTech, SecondaryTech, DOS
In the past I have used something like this, but now my superiors are asking for the number of secondary cases as well...
SELECT PrimaryTech, COUNT(CaseID) as Total
GROUP BY PrimaryTech
I've done a bit of searching, but cant seem to find the answer to my problem.
Select Tech,
sum(case when IsPrimary = 1 then 1 else 0 end) as PrimaryCount,
sum(case when IsPrimary = 0 then 1 else 0 end) as SecondaryCount
from
(
SELECT SecondaryTech as Tech, 0 as IsPrimary
FROM your_table
union all
SELECT PrimaryTech as Tech, 1 as IsPrimary
FROM your_table
) x
GROUP BY Tech
You can group two subqueries together with a FULL JOIN as demonstrated in this SQLFiddle.
SELECT Technician = COALESCE(pri.Technician, sec.Technician)
, PrimaryTech
, SecondaryTech
FROM
(SELECT Technician = PrimaryTech
, PrimaryTech = COUNT(*)
FROM Cases
WHERE PrimaryTech IS NOT NULL
GROUP BY PrimaryTech) pri
FULL JOIN
(SELECT Technician = SecondaryTech
, SecondaryTech = COUNT(*)
FROM Cases
WHERE SecondaryTech IS NOT NULL
GROUP BY SecondaryTech) sec
ON pri.Technician = sec.Technician
ORDER By Technician;
SELECT COALESCE(A.NAME, B.NAME) AS NAME, CASE WHEN A.CASES IS NOT NULL THEN A.CASES ELSE 0 END AS PRIMARY_CASES,
CASE WHEN B.CASES IS NOT NULL THEN B.CASES ELSE 0 END AS SECONDARY_CASES
FROM
(
SELECT COUNT(*) AS CASES, PRIMARYTECH AS NAME FROM YOUR_TABLE
GROUP BY PRIMARYTECH
) AS A
FULL OUTER JOIN
(
SELECT COUNT(*) AS CASES, SECONDARYTECH AS NAME FROM YOUR_TABLE
GROUP BY SECONDARYTECH
) AS B
ON A.NAME = B.NAME