Good Evening,
I have the following sql code and need to replace the NULL values within a sub query. As you can tell from the code I have tried using the ISNULL function and case where = NULL.
Could someone please help?
Select Student_Details.STU_ID ,
( Select case ISNULL( s1stu_disability_type.DISABILITY_TYPE_CD , '' )
when '' then 'NO'
else 'YES'
end
from s1stu_disability_type
Where Student_Details.STU_ID = s1stu_disability_type.STU_ID
and DISABILITY_TYPE_CD = '$HEAR'
) as 'Hearing Disability'
from S1STU_DET as Student_Details
Your where clause in your subquery rejects all rows but those where the column DISABILITY_TYPE_CD is '$HEAR'. Consequently, the case statement will always take the else route, as that column will never, ever be null or empty ('').
What exactly are you trying to do?
You query can better be written as
select sd.STU_ID ,
dt.DISABILITY_TYPE_CD
from S1STU_DET sd
join s1stu_disability_type dt on dt.STU_ID = sd.STU_D
and dt.DISABILITY_TYPE_CD = '$HEAR'
It's almost certian that relationship between student and student disability has a zero-to-many cardinalilty, which is to say that each student has zero or more disabilities.
As a result, your original query, with its correlated subquery, will return 1 row per student, but per the SQL standard, it's luck of the draw as to which matching disability gets selected by the subquery.
My query above will return one row per student with a matching disability. Students without a matching disability are excluded. To change that to include all students, you want to change the [inner] join to a left [outer] join. Each student will then be represented in the result set at least once. If the student has no matching disabilities, all columns for the student disability table will be 'null'.
If, as I suspect, what you're trying to do is identify students as to whether or not they have a hearing disability (or some particular type of disability), you need to summarize things. A query like this will likely do you:
select sd.STU_ID ,
case sign(coalesce(hd.cnt,0))
when 1 then 'YES'
else 'NO'
end as HAS_HEARING_DISABILITY
from S1STU_DET sd
left join ( select STU_ID ,
count(*) as cnt
from s1stu_disability
where DISABILITY_TYPE_CD = '$HEAR'
group by STU_ID
) hd on hd.STU_ID = sd.STU_ID
Try this:
Select Student_Details.STU_ID ,
IsNull(( Select case ISNULL( s1stu_disability_type.DISABILITY_TYPE_CD , '' )
when '' then 'NO'
else 'YES'
end
from s1stu_disability_type
Where Student_Details.STU_ID = s1stu_disability_type.STU_ID
and DISABILITY_TYPE_CD = '$HEAR'
), 'No') as 'Hearing Disability'
from S1STU_DET as Student_Details
Basically, the ISNULL function has to be outside the subquery for it to work the way you want it to. Think of it this way, if the subquery does not return any rows, the output will be null whether you have an isnull check inside the subquery or not.
You shouldn't need a subquery (assuming your subquery only returns one record):
Select
Student_Details.STU_ID,
case WHEN Student_Disability.DISABILITY_TYPE_CD IS NULL
THEN 'NO'
ELSE 'YES'
END
as 'Hearing Disability'
from S1STU_DET as Student_Details
LEFT JOIN s1stu_disability_type Student_Disability
ON Student_Details.STU_ID = Student_Disability.STU_ID
and Student_Disability.DISABILITY_TYPE_CD = '$HEAR'
Related
I am trying to write a query that returns an "Estimated Annual Value", and for this, I am using a Case statement. There are two inner joins involved in the query.
So, the query and gives me result when I am running this piece:
select Users.Id, Name, PhoneNumber, Email, Currency, count(*) as TotalOrders, sum(TotalCustomerAmount) as TotalOrderValue, avg(TotalCustomerAmount) as AverageOrderValue, TsCreate as RegistrationDate, max(TsOrderPlaced) as LastOrderDate, min(TsOrderPlaced) as FirstOrderDate,
CASE
When PromotionsEnabled = 0 then 'Y'
When PromotionsEnabled = 1 then 'n'
else 'undefined'
end as Promotions,
/*CASE
When ((DATEDIFF(day, max(TsOrderPlaced), min(TsOrderPlaced)) >= 6) AND (count(*) > 3)) then ((sum(TotalCustomerAmount)/(DATEDIFF(day, max(TsOrderPlaced), min(TsOrderPlaced))))*365)
Else '-'
end as EstimatedAnnualValue*/
from AspNetUsers with (nolock)
inner join Orders with (nolock) on Orders.UserId = AspNetUsers.Id and Orders.WhiteLabelConfigId = #WhiteLabelConfigId
and Orders.OrderState in (2,3,4,12)
inner join UserWhiteLabelConfigs with (nolock) on UserWhiteLabelConfigs.UserId = AspNetUsers.Id and Orders.WhiteLabelConfigId = #WhiteLabelConfigId
where AspNetUsers.Discriminator = 'ApplicationUser'
group by Users.Id, Name, Number, Currency, Email, TsCreate, PromotionsEnabled
But the problem comes when I am running this with the second CSAE statement, is it because I cannot use the aggregate function before GROUP BY? I am also thinking of using a Subquery
Looking fr some help!!
You need to use aggregation functions. For instance, if you want 'Y' only when all values are 0 or NULL:
(case when max(PromotionsEnabled) = 0 then 'Y'
when max(PromotionsEnabled) = 1 then 'N'
else 'undefined'
end) as Promotions,
I'm not sure if this is the logic you want (because that detail is not in the question). However, this shows that you can use aggregation functions in a case expression.
I'm trying to query come datas and on a spcific case I might have to group datas by multiple values. But most of the time it needs not to be grouped at all. So I'm using multiple CASE WHEN {...} inside the GROUP BY, and all the WHEN basically have the same condition. The problem is that if the condition is met, everything works fine. But if it's false, then the GROUP BY section is empty and the query returns only the first row.
I basically tried to reorganize the quesry in every way that came to my mind, nothing seemed to work, and I didn't find anything conclusive on internet.
I'm using MySql 5.7.
SELECT
{element I want to select}
FROM
{tables}
WHERE
{conditions}
GROUP BY
CASE WHEN (condition) THEN [table].[column] END,
CASE WHEN (condition) THEN [table].[column] END,
CASE WHEN (condition) THEN [table].[column] END
ORDER BY
{...}
Full query :
SELECT
tx.code,
IFNULL(hr.label,'') AS rh_label,
IFNULL(cli.label,'') AS client_label,
DATE(FROM_UNIXTIME(created.value / 1000)) AS Created,
IFNULL(item_enfant.label,'') As Parasite,
IFNULL(item_parent.label,'') As Zone,
CASE
WHEN :perWeek = 'week' THEN SUM(qte.value)
ELSE qte.value
END AS Quantite,
CEILING(DATEDIFF(DATE(FROM_UNIXTIME(created.value / 1000)), DATE(FROM_UNIXTIME(:from / 1000))) / 7) AS Weeks
FROM tx
LEFT JOIN tx_type AS tt ON tt.id = tx.tx_type_id
LEFT JOIN human_resource AS hr ON hr.id = tx.human_resource_id
LEFT JOIN client AS cli ON cli.id = tx.client_id
LEFT JOIN tx_state AS ts ON ts.id = tx.current_tx_state_id
LEFT JOIN workflow_step AS ws ON ws.id = ts.workflow_step_id
LEFT JOIN item AS item_enfant ON item_enfant.item_list_id = tx.item_list_id
JOIN item_type AS ite ON ite.id = item_enfant.item_type_id
LEFT JOIN item_meta AS qte ON qte.item_id = item_enfant.id AND qte.name = 'qtePourRapport'
LEFT JOIN item_prop AS created ON created.item_id = item_enfant.id AND created.name = 'visite.timestamp'
JOIN item AS item_parent ON item_parent.id = item_enfant.parent_item_id
JOIN item_type AS itp ON itp.id = item_parent.item_type_id
WHERE
ite.name = 'parasite' AND
item_enfant.product_id IN (:parasiteIds) AND
itp.name = 'zone' AND
item_parent.product_id IN (:zoneIds) AND
cli.id = (:clientId) AND
ws.logic_id = 600 AND
created.value BETWEEN :from AND :to AND
created.value IS NOT NULL AND qte.value IS NOT NULL
GROUP BY
CASE WHEN :perWeek = 'week' THEN item_enfant.label END, #Parasite
CASE WHEN :perWeek = 'week' THEN item_parent.label END, #Zone
CASE WHEN :perWeek = 'week' THEN CEILING(DATEDIFF(DATE(FROM_UNIXTIME(created.value / 1000)), DATE(FROM_UNIXTIME(:from / 1000))) / 7) END #Weeks
ORDER BY
Created;
I'm getting the datas of the first row alone. And I actually have no idea how to get it just not to group if the condition is not met.
You need a unique value for the aggregation or two separate queries. The simplest method might be union all:
select . . .
from t
where <conditions not to group by>
union all
select . . .
from t
where <conditions to group by>
group by . . .;
You need to be sure that each subquery returns compatible columns.
SELECT
{element I want to select}
FROM
{tables}
WHERE
{conditions}
GROUP BY
CASE WHEN (condition) THEN [table].[column] ELSE [some unique value of same data-type as column] END,
CASE WHEN (condition) THEN [table].[column] ELSE [some unique value of same data-type as column] END,
CASE WHEN (condition) THEN [table].[column] ELSE [some unique value of same data-type as column] END
ORDER BY
{...}
I guess the missing ELSE clause will evaluate to NULL. This is constant, thus all rows will be in the same group, thus there will be only one row returned for this group. To avoid grouping you need unique values over all returned rows in the combination of the grouping-elements (not in every single grouping-element as stated erlier).
EDIT
Thus the soultion from the comment might be easier: Just add another grouping-element CASE WHEN !(condition) THEN CONCAT([different elements making it unique]) END
I am working in SQL server 2012. I have to write a sql statement where I first assign a value to [Pay_Type], which is a non-existing column (not sure whether it can be called as variable or not) and based upon its value I want to use it in another case statement as shown below
SELECT sp.First_Name, [Pay_Type] = CASE WHEN NOT EXISTS(SELECT '1' FROM
PERSON_SALARY ps WHERE ps.PARTY_ID = sp.PARTY_ID and ps.END_DATE IS NULL)
THEN 'Hourly' ELSE 'Salary' END,
HOURLY_RATE = CASE WHEN [Pay_Type] = 'Hourly' THEN pj.HOURLY_RATE ELSE
'0.00' END
FROM SEC_PERSON sp
LEFT OUTER JOIN PERSON_JOB pj ON sp.PERSON_ID = pj.PERSON_ID
WHERE sp.END_DATE IS NOT NULL
But I am getting "Invalid column name 'Pay_Type' " error.
Column aliases cannot be re-used in the same SELECT where they are define. The typical answer is to use a subquery or CTE. I also like using a lateral join:
SELECT sp.First_Name, s.Pay_Type,
HOURLY_RATE = (CASE WHEN s.Pay_Type = 'Hourly' THEN pj.HOURLY_RATE ELSE
'0.00' END)
FROM SEC_PERSON sp LEFT OUTER JOIN
PERSON_JOB pj
ON sp.PERSON_ID = pj.PERSON_ID OUTER APPLY
(SELECT (CASE WHEN NOT EXISTS (SELECT 1
FROM PERSON_SALARY ps
WHERE ps.PARTY_ID = sp.PARTY_ID and ps.END_DATE IS NULL
)
THEN 'Hourly' ELSE 'Salary'
END) as PayType
) s
WHERE sp.END_DATE IS NOT NULL
I have a piece of code which runs fine. However, when i am introducing a "case when" statement in the select clause, I get the "group function is not allowed here" error and I cannot fix it (the issue relates to the last Group by function in my code)
Any idea why (don't be put off by the code, it is 3 joins together, apparently the issue is caused by the last Group By statement) ?
Thank you!
SELECT
Trans_Table.MTAGRE01_NO
, (case when Cash. MTAGRE01_NO = Trans_Table. MTAGRE01_NO
then (SUM(Trans_Table.MTTRANS01_VALUENCU)*-1)
else SUM(Trans_Table.MTTRANS01_VALUENCU) END) AS MTTRANS01_VALUENCU
FROM MTTRANS01 Trans_Table
INNER JOIN RUTRANTYPE01 Trans_Type
ON Trans_Type.RUTRANTYPE01_CODE = Trans_Table.RUTRANTYPE01_CODE
LEFT JOIN(
SELECT
MTAGRE01_NO
,CASE WHEN SRAGRESTAT01_CODE = 'COLL' THEN MTAGRE01_AGRESTATDATE END AS Date_Fr
from MTAGRE01
where CASE WHEN SRAGRESTAT01_CODE = 'COLL' THEN MTAGRE01_AGRESTATDATE END is not null
) F_Date
ON F_Date.MTAGRE01_NO = Trans_Table.MTAGRE01_NO
LEFT JOIN(
SELECT
Trans_Table.MTAGRE01_NO
FROM MTTRANS01 Trans_Table
INNER JOIN RUTRANTYPE01 Trans_Type ON Trans_Type.RUTRANTYPE01_CODE = Trans_Table.RUTRANTYPE01_CODE
GROUP BY
Trans_Table.MTAGRE01_NO, Trans_Type.RUTRANTYPE01_CODE, Trans_Type.RUTRANTYPE01_DESCRIPTION
) Cash
ON Cash.MTAGRE01_NO = Trans_Table.MTAGRE01_NO
where Trans_Type.SRPROCTYPE01_CODE in ('C','D')
and Trans_Table.MTTRANS01_VALUEDATE >= F_Date.Date_Fr
GROUP BY
Trans_Table.MTAGRE01_NO
, (case when Cash. MTAGRE01_NO = Trans_Table. MTAGRE01_NO
then (SUM(Trans_Table.MTTRANS01_VALUENCU)*-1)
else SUM(Trans_Table.MTTRANS01_VALUENCU) END);
I believe it's hung up on the sum inside the case statement. 2 routes to correct that I can see, likely alot more:
This is a little hacky, but it'll work and give results fast. Change your case:
SELECT
Trans_Table.MTAGRE01_NO
, (case when Cash. MTAGRE01_NO = Trans_Table. MTAGRE01_NO
then ((Trans_Table.MTTRANS01_VALUENCU)*-1)
else (Trans_Table.MTTRANS01_VALUENCU) END) AS MTTRANS01_VALUENCU
Remove the case from the group by.
Now call your entire query a sub query
Select MTAGRE01_NO, sum(MTTRANS01_VALUENCU)
(your entire query)a
You other option that takes a bit more work...in your initial from statement:
MTTRANS01 Trans_Table
Change that to a subquery that joins to the trans table and returns
case when Cash. MTAGRE01_NO = Trans_Table. MTAGRE01_NO
then ((Trans_Table.MTTRANS01_VALUENCU)*-1)
else (Trans_Table.MTTRANS01_VALUENCU) END as MTAGRE01_NO
Then join to that subquery and do a simple sum in your main query.
Hopefully that all makes sense, ask questions if you need clarifications
The following SQL works as expected if ProjectStatusType.Name is not null. Therefore I put the case statement which replace null value with 'Not specified'. What I am trying to do is to add a where statement to display ProjectStatusType.Name = 'Not Specified', but no data gets returned, although there is a record in database with null projectstatustype.name. Please advise; what is another way, or how can I fix the SQL query?
SELECT PersonResponsible.Name AS TeamLeaderName,
CASE
WHEN ProjectStatusType.Name IS NULL THEN 'Not Specified'
ELSE COALESCE(ProjectStatusType.Name, '')
END AS ProjectStatusName,
Project.ProjectTitle AS Title,
ProjectStatus.DateStatus,
Project.ProjectId,
Project.ContactName,
BusinessDivision.Name AS BusinessUnit,
BusinessUnit.Name AS WorkSection,
ProjectSubGroup.Name AS ProjectSubGroupName,
ProjectGroup.Name AS ProjectGroupName,
Project.DateRequested
FROM BusinessUnit
INNER JOIN BusinessDivision ON BusinessUnit.BusinessDivisionId = BusinessDivision.BusinessDivisionId
INNER JOIN ProjectCode ON BusinessUnit.BusinessUnitId = ProjectCode.BusinessUnitId
RIGHT OUTER JOIN Project
INNER JOIN ProjectSubGroup ON Project.ProjectSubGroupId = ProjectSubGroup.ProjectSubGroupId
INNER JOIN ProjectGroup ON ProjectSubGroup.ProjectGroupId = ProjectGroup.ProjectGroupId ON ProjectCode.ProjectCodeId = Project.ProjectCodeId
LEFT OUTER JOIN PersonResponsible ON Project.PersonResponsibleId = PersonResponsible.PersonResponsibleId FULL
OUTER JOIN ProjectStatusType
INNER JOIN ProjectStatus ON ProjectStatusType.ProjectStatusTypeId = ProjectStatus.ProjectStatusTypeId
AND ProjectStatus.ProjectStatusId IN
(SELECT MAX(ProjectStatusId) AS ProjectStatusId
FROM ProjectStatus
GROUP BY ProjectId) ON Project.ProjectId = ProjectStatus.ProjectId
WHERE ProjectStatus ProjectStatusType.Name ='Not Specified'
Here is a great chart from Itzik Ben-Gan on how SQL server processes a query. The order is different than how we write T-SQL.
Thus the solution by rutter might miss the empty string.
If I was doing this type of business logic alot, I would write a function that would take both the empty string or null value and return a string 'unknown'. Call this function in the query and filter by 'unknown'.
The example below creates a temporary table, loads the table with data, and returns both the empty string and null value converted to the adjust name 'Not Specified'.
I hope this helps.
I always refer to the logical processing chart when queries do not work the way I think they should.
Good luck
John
--
-- Logical query processing
--
-- From, Where, Group By, Having, Select (expression, distince, top), order by
-- sample table
create table #status
( id int identity(1,1),
name varchar(50) null
);
-- Sample data
insert into #status values
(''),
(null),
('www.craftydba.com');
-- Return rows with null or empty string
select
case when ltrim(name) = '' then 'Not Specified'
else coalesce(name, 'Not Specified') end as adjusted_named,
name
from #status
where
ltrim(name) = '' or
coalesce(name, 'Not Specified') = 'Not Specified';
Two points:
First, a CASE checking for null seems redundant to a COALESCE expression.
This should be simpler:
SELECT COALESCE(ProjectStatusType.Name, 'Not Specified') AS ProjectStatusName
Second, comparing to ProjectStatusType.Name (the value in your table) is not the same as comparing to ProjectStatusName (the value you selected).
Try a WHERE clause closer to this:
WHERE ProjectStatusName = 'Not Specified'