Convert rows into columns in sub-query - sql

I'm trying to convert rows into columns when using this in a subquery query like:
select distinct
bqtID, bqtName, bqtCity, bqtStatus, bqtManagerName,
(select
max(case when serName = 'Capacity' then serStatus end) Capacity,
max(case when serName = 'Parking' then serStatus end) Parking
from
tblService
where
serBqtID = bqtID),
from
View_BanquetList
where
bqtID = 1
I get this error:
Only one expression can be specified in the select list when the subquery is not introduced with EXISTS.
While when I used it separately then it works:
select
max(case when serName = 'Capacity' then serStatus end) Capacity,
max(case when serName = 'Parking' then serStatus end) Parking
from
tblService
where
serBqtID = 1
Results:
Capacity Parking
-------- -------
101-200 51-100
Why is it not converting multiple rows into columns in sub-query?

You are trying to return two columns as one in the select list. That doesn't work. I'm not an expert on SQL Server, but with Oracle there would be at least three options.
Move the subselect to a with-clause and then join with it.
Use two sub-selects, one for capacity and one for parking.
Move the sub-select to the from clause and use a subselect that becomes a table, which is then joined.
I think all should work with SQL Server as well. Option 3 is closest to what you have now.
EDIT: try this:
select distinct
v.bqtID, v.bqtName, v.bqtCity, v.bqtStatus, v.bqtManagerName,
t.Capacity, t.Parking
from
(select
serBqtID,
max(case when serName = 'Capacity' then serStatus end) Capacity,
max(case when serName = 'Parking' then serStatus end) Parking
from
tblService
group by
serBqtID) t
inner join
View_BanquetList v on t.serBqtID = v.bqtID
where
v.bqtID = 1

Related

Counting Booleans for Distinct and Non Distinct ID numbers

I have a simple table that looks like the following PNG file from the following join:
SELECT *
FROM tableA A
JOIN tableB B ON B.Main_SPACE_ID = A.Main_SPACE_ID
Table A contains Guest_ON and User_Controls (last 2 columns) and Table B contains Trigger_ON and DOCX_ON.
Issue:
What I am trying to do is count all the True's for each tableB.Subspace_ID and the DISTINCT trues for tableA.Main_SPACE_ID.
The problem is that subspace_ID from table B lives within the main_space_id from table A and therefore creates a situation where I am double counting.
I only want to count the trues for a distinct Main_space ID
Current Data Model
Desired Output:
From the above screenshot, I am trying to get a count of true values without double counting in the case for tableA_MAIN_SPACE_ID.
As you can see, each row is counted for true values as it relates to the subspace_ID (table B) for totals of 12 and 8 (1 if True, 0 if False) and for tableA, I am only counting distinct values so we only count Trues for a single MainspaceID and avoid recounting them.
If someone can advise on how to get this output from my current data model that would be very helpful!
My attempt as follows double counts trues for the Main space ID column..
SELECT
count(CASE WHEN B.TRIGGER_ON THEN 1 END) as TRIGGER_ON,
count(CASE WHEN B.DOCX_ON THEN 1 END) as DOCX_ON,
count(CASE WHEN A.GUEST_ON THEN 1 END) as SPRINTS,
count(CASE WHEN A.USER_CONTROLS THEN 1 END) as SPRINTS
FROM DataModel
What I am trying to do is count all the True's for each tableB.Subspace_ID and the DISTINCT trues for tableA.Main_SPACE_ID.
You can use conditional aggregation. In Snowflake, you can use the convenient COUNT_IF() for the first two columns. However, for the second two, you need COUNT(DISTINCT) with conditional logic:
SELECT COUNT_IF( B.Trigger_on ) as Trigger_On,
COUNT_IF( B. DOCX_ON ) as DOCX_ON,
COUNT(DISTINCT CASE WHEN A.GUEST_ON THEN A.Main_SPACE_ID END) as GUEST_ON,
COUNT(DISTINCT CASE WHEN A. USER_CONTROLS THEN A.Main_SPACE_ID END) as USER_CONTROLS
FROM tableA A JOIN
tableB B
ON B.Main_SPACE_ID = A.Main_SPACE_ID;
Mabye:
SELECT
COUNT(CASE WHEN B.TRIGGER_ON THEN 1 END) AS TRIGGER_ON,
COUNT(CASE WHEN B.DOCX_ON THEN 1 END) AS DOCX_ON,
(SELECT COUNT(*) FROM (SELECT DISTINCT A.MAIN_SPACE_ID, A.GUEST_ON FROM DataModel WHERE A.GUEST_ON = TRUE) A) AS GUEST_ON
(SELECT COUNT(*) FROM (SELECT DISTINCT A.USER_CONTROLS, A.GUEST_ON FROM DataModel WHERE A.USER_CONTROLS = TRUE) A) AS USER_CONTROLS
FROM DataModel

SQL count conditioning without the 0 values

I am trying to run a case count on SQL but I want the results without the 0 how do I do that?
Select ClubName,
ClubType,
Country,
Concat(Count(case when GameResult like 'w%' then 1 else NULL end), ' ','wins'),
Count(Case when GameResult like 'l%' then 1 end) AS Losses
from ClubDim,CountryDim,GamesFact
where ClubDim.CountryID = CountryDim.CountryID
And ClubDim.ClubID = GamesFact.ClubID
GROUP BY ClubName,ClubType,Country,GameResult
Having ClubType = 'Professional'
That's the code and I am getting a lot of zeros and my target is to count losses and wins in two separate columns
It's obviously not possible to test without sample data however you should be using sum not count here. Your having criteria should be part of the where clause as you are not filtering on an aggregate. I would also recommend using proper join syntax which has been standard since 1992! However this should give you expected results, I suspect.
Select ClubName,
ClubType,
Country,
Concat(sum(case when GameResult like 'w%' then 1 else 0 end), ' ','wins'),
Sum(Case when GameResult like 'l%' then 1 else 0 end) AS Losses
from ClubDim,CountryDim,GamesFact
where ClubDim.CountryID = CountryDim.CountryID and ClubDim.ClubID = GamesFact.ClubID
and ClubType = 'Professional'
GROUP BY ClubName,ClubType,Country,GameResult
The issue is that you have put gameResult in the group by.
More importantly, you need to learn proper, explicit, standard, readable JOIN syntax. Doing a Cartesian product and filtering in the WHERE clause is just awkward. Not using proper syntax is outdated:
select cl.ClubName, cl.ClubType, co.Country,
Concat(Count(case when g.GameResult like 'w%' then 1 else NULL end), ' ', 'wins'),
Count(Case when g.GameResult like 'l%' then 1 end) AS Losses
from ClubDim cl join
CountryDim co
on cl.CountryID = co.CountryID join
GamesFact g
on cl.ClubID = g.ClubID
where cl.ClubType = 'Professional'
group by cl.ClubName, cl.ClubType, co.Country;
In addition:
Note the use of table aliases. These should be abbreviations for the table names.
I did my best to qualify all columns, so it is clear what tables they come from. Of course, your question doesn't provide this information, so this is just guessing.
Filter before aggregating by using a WHERE clause rather than filtering after aggregating with a HAVING. Use HAVING when you want to filter on the results of aggregations (such as COUNT(*)).
You can try below query -
SELECT ClubName,
ClubType,
Country,
CASE WHEN Wins > 0 THEN CONCAT(Wins , ' wins') ELSE NULL END WINS,
loses
FROM (SELECT ClubName,
ClubType,
Country,
Count(case when GameResult like 'w%' then 1 else NULL end) AS Wins,
Count(Case when GameResult like 'l%' then 1 end) AS Losses
FROM ClubDim CLD
JOIN CountryDim COD ON CLD.CountryID = COD.CountryID
JOIN GamesFact GF ON CLD.ClubID = GF.ClubID
where ClubType = 'Professional'
GROUP BY ClubName,ClubType,Country) X;

SQL Joined Tables - Multiple rows on joined table per 'on' matched field merged into one row?

I have two tables I am pulling data from. Here is a minimal recreation of what I have:
Select
Jobs.Job_Number,
Jobs.Total_Amount,
Job_Charges.Charge_Code,
Job_Charges.Charge_Amount
From
DB.Jobs
Inner Join
DB.Job_Charges
On
Jobs.Job_Number = Job_Charges.Job_Number;
So, what happens is that I end up getting a row for each different Charge_Code and Charge_Amount per Job_Number. Everything else on the row is the same. Is it possible to have it return something more like:
Job_Number - Total_Amount - Charge_Code[1] - Charge_Amount[1] - Charge_Code[2] - Charge_Amount[2]
ETC?
This way it creates one line per job number with each associated charge and amount on the same line. I have been reading through W3 but haven't been able to tell definitively if this is possible or not. Anything helps, thank you!
To pivot your resultset over a fixed number of columns, you can use row_number() and conditional aggregation:
select
job_number,
total_amount,
max(case when rn = 1 then charge_code end) charge_code1,
max(case when rn = 1 then charge_amount end) charge_amount1,
max(case when rn = 2 then charge_code end) charge_code2,
max(case when rn = 2 then charge_amount end) charge_amount2,
max(case when rn = 3 then charge_code end) charge_code3,
max(case when rn = 3 then charge_amount end) charge_amount3
from (
select
j.job_number,
j.total_amount,
c.charge_code,
c.charge_amount,
row_number() over(partition by job_number, total_amount order by c.charge_code) rn
from DB.Jobs j
inner join DB.Job_Charges c on j.job_number = c.job_number
) t
group by job_number, total_amount
The above query handes up to 3 charge codes and amounts par job number (ordered by job codes). You can expand the select clause with more max(case ...) expressions to handle more of them.

How to use pivote to find out the max value from a row with three columns, that is max value out of three columns

I have following table named as 'Table',
Where I want result like following table where if you take first row and last three columns I want value to be 56.
I want sql server code for above table 'Table' and result to be second table. Here MaxV-1 and MaxV-2 are dependent on 'Number' column. MaxV-1 is max value out of FirstV, SecondV and ThirdV when Number is equal to 1 and same logic for MaxV-2.
One method is an unpivot and conditional aggreation:
select t.model,
max(case when t.number = 1 then t.pro_code end) as pro_code_1,
max(case when t.number = 2 then t.pro_code end) as pro_code_2,
max(case when t.number = 1 then v.v end) as max_val_1,
max(case when t.number = 2 then v.v end) as max_val_2
from t cross apply
(select max(v.v) as v
from (values (t.firstv), (t.secondv), (t.thirdv)) v(v)
) v
group by t.model;

pivot table returns more than 1 row for the same ID

I have a sql code which I am using to do pivot. Code is as follows:
SELECT DISTINCT PersonID
,MAX(pivotColumn1)
,MAX(pivotColumn2) --originally these were in 2 separate rows)
FROM(SELECT srcID, PersonID, detailCode, detailValue) FROM src) AS SrcTbl
PIVOT(MAX(detailValue) FOR detailCode IN ([pivotColumn1],[pivotColumn2])) pvt
GROUP BY PersonID
In the source data the ID has 2 separate rows due to having its own ID which separates the values. I have now pivoted it and its still giving me 2 separate rows for the ID even though i grouped it and used aggregation on the pivot columns. Ay idea whats wrong with the code?
So I have all my possible detailCode listed in the IN clause. So I have null returned when the value is none but I want it all summarised in 1 row. See image below.
If those are all the options of detailCode , you can use conditional aggregation with CASE EXPRESSION instead of Pivot:
SELECT t.personID,
MAX(CASE WHEN t.detailCode = 'cas' then t.detailValue END) as cas,
MAX(CASE WHEN t.detailCode = 'buy' then t.detailValue END) as buy,
MAX(CASE WHEN t.detailCode = 'sel' then t.detailValue END) as sel,
MAX(CASE WHEN t.detailCode = 'pla' then t.detailValue END) as pla
FROM YourTable t
GROUP BY t.personID