I have a table jobs with a column StartDate that is often null. If it is not null this is what I want to inner join with a table quarters on, otherwise I want to inner join on some other conditions. This is sort of what I want:
INNER JOIN Quarters q
ON (IF j.StartDate IS NOT NULL (j. StartDate BETWEEN GETDATE() and q.EndDate)
ELSE **Some other condition**)
The error that comes up when this is run is that there is incorrect syntax near the keyword 'IF'
Does anyone know the correct syntax for this?
Thanks in advance for your help!
INNER JOIN Quarters q ON
(j.StartDate IS NOT NULL AND j. StartDate BETWEEN GETDATE() and q.EndDate)
OR
(j.StartDate IS NULL AND **Some other condition**)
The easiest way to handle this is just to treat it as a logical operation:
ON (j.StartDate IS NOT NULL
and j. StartDate BETWEEN GETDATE() and q.EndDate)
OR (some other condition)
Try
CASE WHEN j.StartDate IS NULL THEN somevalue ELSE some_other_value END
the syntax is
CASE WHEN some_boolean_expression THEN some_value_column_or_expression
WHEN some_boolean_expression THEN some_value_column_or_expression
... (repeat when as many times you need it)
ELSE some_value_column_or_expression
END
Note: Else can be ommited.
also see the links
http://www.craigsmullins.com/ssu_0899.htm
http://msdn.microsoft.com/en-us/library/ms181765.aspx
Related
I'm trying to run a SQL query but an error happens when I run it.
Error:
[Code: -811, SQL State: 21000]
The result of a scalar fullselect, SELECT INTO statement, or VALUES INTO statement is more than one row..
SQLCODE=-811, SQLSTATE=21000, DRIVER=4.19.49
This is the SQL query that I am trying to run, I believe there is a problem with my CASE statement, I'm running out of solution. Please help, thanks a lot!
SELECT
ES.SHPMNT_REF,
(CASE
WHEN (ES.SERVICE_PROVIDER_NAME) IS NULL
THEN (SELECT BRDB.EXPORT_ONHAND.SERVICE_PROVIDER_NAME
FROM BRDB.EXPORT_ONHAND
WHERE BRDB.EXPORT_ONHAND.SHPMNT_REF = ES.SHPMNT_REF)
ELSE (ES.SERVICE_PROVIDER_NAME)
END) AS SP
FROM
BRDB.EXPORT_SHIPMENT ES
WHERE
ES.DATE_CREATE > CURRENT TIMESTAMP - 30 DAYS
I think this is what you are after. Joining on the table data you might need, then letting COALESCE check for null and get the other data if it is.
SELECT
ES.SHPMNT_REF,
COALESCE(ES.SERVICE_PROVIDER_NAME, OH.SERVICE_PROVIDER_NAME) AS SP
FROM BRDB.EXPORT_SHIPMENT ES
LEFT JOIN BRDB.EXPORT_ONHAND AS OH
ON ES.SHPMNT_REF = OH.SHPMNT_REF
WHERE
ES.DATE_CREATE > CURRENT TIMESTAMP - 30 DAYS
Maybe you should put inside the case:
THEN (SELECT TOP 1 BRDB.EXPORT_ONHAND.SERVICE_PROVIDER_NAME
The error is thrown because your subquery returns multiple values.
The best way would be joining the two table first and then get the value you need when the value is NULL.
That should work:
SELECT
ES.SHPMNT_REF
,CASE
WHEN ES.SERVICE_PROVIDER_NAME IS NULL
THEN EO.SERVICE_PROVIDER_NAME
ELSE ES.SERVICE_PROVIDER_NAME
END AS 'SP'
FROM BRDB.EXPORT_SHIPMENT ES
LEFT JOIN BRDB.EXPORT_ONHAND EO
ON ES.SHPMNT_REF = EO.SHPMNT_REF
WHERE ES.DATE_CREATE > CURRENT TIMESTAMP - 30 DAYS
I have 2 tables:
tblAbsence
Name Start End Status
John 4/2/18 4/5/18 Approved
Sue 5/1/18 5/10/18 Denied
tblManning
Date Required
4/1/18 3
4/2/18 4
4/3/18 2
I would like to be able to update tblAbsence.Status to "Approved" as long as the Required value during the absence request doesn't exceed an arbitrary limit (4 for example).
After looking at #Jeffrey's proposal and experimenting I think I need an Update query which Sets [Status]= Approved when leave request is not found in query below. The below query will tell me if a request has any days that exceed the Limit.
SELECT tblAbsence.name, tblAbsence.start, tblAbsence.end
FROM tblAbsence, tblManning
WHERE tblManning.Date >= Int([tblAbsence].[Start]) And tblManning.Date <= [tblAbsence].[End] AND tblManning.[Req]>3
GROUP BY tblAbsence.name, tblAbsence.[Start], tblAbsence.end;
I renamed the above query as qryLv and tried this Left Join but it tells me I must use an updatable query????
Update tblAbsence a
Left Join qryLv L
ON L.name = a.name AND l.start = a.start
SET a.Status = "Approved"
WHERE l.name is null;
Your error is showing because you have to either equate or use IN/EXISTS with a variable when using subqueries in WHERE clauses. However, I'm not sure you need a subquery, I think something like this will work:
UPDATE tblAbsence SET tblAbsence.Status = "Approved"
FROM tblAbsence, tblManning
WHERE tblManning.Date > tblAbsence.Start
AND tblManning.Date <= tblAbsence.End + #23:59:59#
AND tblManning.Required < 4;
Ok, kinda missed that part, you will need a subquery. I think you need to use NOT EXISTS just to check if your subquery returns any values or not and that should work for you.
UPDATE tblAbsence SET tblAbsence.Status = "Approved"
FROM tblAbsence
WHERE NOT EXISTS (
SELECT NULL
FROM tblManning
WHERE tblManning.Date > tblAbsence.Start
AND tblManning.Date <= tblAbsence.End + #23:59:59#
AND tblManning.Required < 4);
I think you can use NULL in the subquery since you are not returning records, just a boolean, but if it doesn't work you can replace it with *.
I'm trying to make an average of two columns that may or not contain in the second one Null values. Can someone help me get an idea of how to make an operation between these values?
select
nib, primeiroTitular, segundoTitular,
((YEAR(GETDATE()) - YEAR(P1.dataNascimento)) +
(YEAR(GETDATE()) - YEAR(P2.dataNascimento)))/2 as média
from
ContasBancarias
left join
Pessoas P1 on P1.bi = ContasBancarias.primeiroTitular
left join
Pessoas P2 on P2.bi = ContasBancarias.segundoTitular
Here is what you can do. I changed the way that you do calculation between the two dates I used the DATEDIFF() function Next time try to indent your code when you ask a question it's easier for the people when they try to read your code.
SELECT nib
, primeiroTitular
, segundoTitular
,(DATEDIFF(YEAR,GETDATE(), CASE
WHEN P1.dataNascimento IS NULL
THEN GETDATE()
ELSE P1.dataNascimento
END )
+ DATEDIFF(YEAR,GETDATE(),CASE
WHEN P2.dataNascimento IS NULL
THEN GETDATE()
ELSE P2.dataNascimento
END) )/2 as média
FROM ContasBancarias
LEFT JOIN Pessoas P1
ON P1.bi = ContasBancarias.primeiroTitular
LEFT JOIN Pessoas P2
ON P2.bi = ContasBancarias.segundoTitular
Assuming only the second column could be NULL try this -
([Column1] + ISNULL(Column2,0))/2 AS [Average]
In the interest of accuracy, I would recommend NOT INCLUDING any NULLs in your equation, since NULL means "don't know the value", "don't know what the value is", or "don't know if this value is relevant at all". To assign a zero value to NULL is to skew the results.
Most accurate results, use the WHERE clause to eliminate any row with NULL from the calculations, or the ISNULL function.
I am creating standings for the English Premier League. I need to make standings for home and away records. One of the teams has no home losses, therefore SQL counts this as a NULL not a 0. I want to replace the NULL with a 0. I am having trouble getting the desired results.
select ht.Team,
CASE when FTR IS NULL then 0
else count(ht.FTR)
END as LossesHome
Into dbo.HomeLoss
from dbo.HomeTeam ht
where FTR = 'A'
group by ht.Team, ht.FTR
I thought that this would give me the desired results, however, it only returns 19 teams (there are 20).
I have read other questions that use coalesce and isnull functions and tried them as well but I still only get 19 teams returned.
Any help would be appreciated. If anyone needs more information or code please let me know.
Thanks again.
Looks like the problem is in your WHERE clause where you are not including the FTR null value.
select ht.Team,
CASE when FTR IS NULL then 0
else count(ht.FTR)
END as LossesHome
Into dbo.HomeLoss
from dbo.HomeTeam ht
where FTR = 'A' or FTR is null
group by ht.Team
SELECT ISNULL(myColumn, 0 ) FROM myTable
you can use coalesce function:-
select ht.Team,
coalesce(count(ht.FTR) as count_LossesHome,0)
Into dbo.HomeLoss
from dbo.HomeTeam ht
where FTR = 'A'
group by ht.Team
I have an update statement that I am using to change the value of my building field if certain criteria is met.
Here is where I tell it to set my building value to the result of my select statement
update Table set Building = (select case when child.date determined between child.entry date and child.withdrawal date
then child.building else child.[offender bldg]end
Then my select statement is then a product of another select statement where I have to define the value for date3 because it has nulls and I need it force it to be current date to ensure that I am capturing all the records that need to be updated.
from (select w.BUILDING, [Withdrawal Date] = case when WITHDRAWAL_DATE is null then GETDATE() else w.WITHDRAWAL_DATE end,a.DATE_DETERMINED,w.ENTRY_DATE,a.RESP_BUILDING,o.BUILDING[Offender Bldg]
from dbo._temp_disc_off a inner join dbo.offender o on (a.INCIDENT_ID = o.INCIDENT_ID) inner join dbo.entry w on (o.PERSON_ID = w.STUDENT_ID))child</b>
This next section is associated to the first select statement and filters for buildings that meet either criteria
where child.DATE_DETERMINED between child.ENTRY_DATE and child.[Withdrawal Date] and child.RESP_BUILDING is null
or child.DATE_DETERMINED between child.ENTRY_DATE and child.[Withdrawal Date] and child.RESP_BUILDING <> child.[Offender Bldg])</b>
I have to set it up this way, because I need to compare to a date and not a null value because my result set goes from 2425 to 461 if I don't set withdrawal date to getdate() if null.
When I run the query I get the following error:
Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression.
I know that it is trying to return multiple values, and that is what I want. But when I try to use IN instead of = I get an incorrect syntax error.
The statement is not being used in a stored procedure, I am just trying to mass update some records. Please help, and please over look the fact that my syntax is a little off.
Thanks in advance
Updated My Question with Full Block
*here is my full statement in one block, I made some changes to it since posting, but I am trying to do the same update the temp disc off action table resp_building field. I can only do this if the date_determined is between the entry and withdrawal dates, but in some cases the withdrawal date is null, so I add a sub select where I provide a value for withdrawal date.
update dbo._temp_disc_off_action
set RESP_BUILDING = (
select case when child.DATE_DETERMINED between child.entry_date and child.[Withdrawal Date]
then child.BUILDING else child.[Offender Bldg] end
from (
select w.BUILDING, [Withdrawal Date] = case when WITHDRAWAL_DATE is null
then GETDATE()
else w.WITHDRAWAL_DATE end,
a.DATE_DETERMINED, w.ENTRY_DATE, a.RESP_BUILDING, o.BUILDING [Offender Bldg]
from dbo._temp_disc_off_action a
inner join dbo.DISC_OFFENDER o
on a.INCIDENT_ID = o.INCIDENT_ID
inner join dbo.REG_ENTRY_WITH w
on o.PERSON_ID = w.STUDENT_ID
where w.BUILDING = 41) child
where child.DATE_DETERMINED between child.ENTRY_DATE and child.[Withdrawal Date]
and child.RESP_BUILDING is null
or child.DATE_DETERMINED between child.ENTRY_DATE and child.[Withdrawal Date]
and child.RESP_BUILDING <> child.[Offender Bldg])
The problem is:
update Table set Building = (sub query).
What you are trying to do is update a single column, Building, with a single value returned from the sub query. However, your sub query is returning more than one value. So instead of Building 4, it gives you Building 4, 10, and 19. Sql Server can't set a single column to multiple values and throws the error.
The easiest way to debug is to convert your entire update statement into a select statement that selects the original value and the value you want to update to. You can examine the result select and see why you have duplicate rows from your sub select and figure out how to return a single value, or potentially concatenate or group multiple rows together to return a single value.
I figured it out, I was completely over complicating things and was able to update the fields I wanted by simply running a statement where I included CASE statement in my where clause. That allowed me check if the date determined is between the two dates, while replacing null values of my withdrawal date with current date. Here is my statement below:
UPDATE dbo._temp_disc_off_action SET RESP_BUILDING = w.BUILDING
FROM dbo._temp_disc_off_action a JOIN dbo.DISC_OFFENDER o ON (a.INCIDENT_ID = o.INCIDENT_ID) JOIN dbo.REG_ENTRY_WITH w ON (o.PERSON_ID = w.STUDENT_ID)
WHERE a.DATE_DETERMINED BETWEEN w.ENTRY_DATE AND CASE WHEN w.WITHDRAWAL_DATE IS NULL THEN GETDATE() ELSE w.WITHDRAWAL_DATE END AND a.RESP_BUILDING IS NULL AND **o.BUILDING = '41'
**OR a.DATE_DETERMINED BETWEEN w.ENTRY_DATE AND CASE WHEN ** w.WITHDRAWAL_DATE **IS NULL THEN GETDATE() ELSE w.WITHDRAWAL_DATE END
AND a.RESP_BUILDING <> o.BUILDING AND o.BUILDING = '41'