IS NULL being ignored - sql-server

I am trying to run a query in T-SQL to pull back a data set based on a column being null.
This is a simplified version of the code:
SELECT
T1.Col1, T1.Col2,
T1.Col3, T1.Col4
FROM
table1 AS T1
INNER JOIN
table2 AS T2 ON T1.Col2 = T2.Col3
WHERE
T2.Col4 IS NULL
Problem is, the result includes rows where T2.Col4 are NULL and also not NULL, it's like the WHERE clause doesn't exist.
Any ideas would be greatly
UPDATE - full version of code:
SELECT
M.ref
,C.cname
,CL.clname
,C.ccity
,M.productLine
,M.code
,CL.date
,M.dept
,DPT.group
,TK2.tkname
,TK2.tkdept
FROM DB.dbo.manage AS M
OUTER JOIN DB.dbo.ClientManageRelationship AS CMR
ON CMR.RelatedEntityID = M.EntityID
OUTER JOIN DB.dbo.Client AS C
ON C.EntityID = CMR.EntityID
INNER JOIN DB.dbo.ManageCustomerRelationship AS MCR
ON MCR.EntityID = M.EntityID
INNER JOIN DB.dbo.Customer AS CL
ON CL.EntityID = MCR.RelatedID
INNER JOIN DB.dbo.timek AS TK
ON TK.tki = M.tkid
LEFT JOIN (SELECT Group = division, [Department] = newdesc, deptcode FROM DB.csrt.vw_rep_p_l_dept) AS DPT
ON tkdept = DPT.dept
LEFT JOIN (SELECT Name = TK2.tkfirst + ' ' + TK2.tklast, TK2.tki, TK2.dept, TK2.loc FROM DB.dbo.timek as TK2 WITH(NOLOCK)) AS TK2
ON TK2.tki = M.tkid
WHERE DPT.Department = 'Casualty'
AND UPPER (C.ClientName) LIKE '%LIMITED%'
AND CL.date > '31/12/2014'
AND CL.Date IS NULL
AND TK.tkloc = 'loc1' OR TK.tkloc = 'loc2'
ORDER BY M.ref

My first answer would be because you're using INNER JOIN. This only returns matches between the 2 tables. TRY FULL OUTER JOIN which will return all values regardless of matches and will include NULLS.
If you were looking to return all rows regardless of matches including NULLS from only one of the tables then use RIGHT or LEFT JOIN.
Say i had 2 tables ('Person' and 'Figure'). Not every person may have entered a figure on any one day. But an example may be i want to return all people regardless of whether they entered a figure or not on a certain day.
My initial approach to this would be a LEFT join because i want to return of all the people(left table) regardless of there being any matches in the figure table(right table)
FROM Person P
LEFT JOIN Figure F
ON P.ID = F.ID
This would produce a result such as
Name Figure
Sam 20
Ben 30
Matt NULL
Simon NULL
Whereas,
An inner join would produce only matching values not including nulls
Name Figure
Sam 20
Ben 30
Left join works the same way as right join but in the opposite direction. This is most likely the problem you were facing. But i hope this helped

I think the problem is in the last part of the where condition.
You should use brackets.
`WHERE DPT.Department = 'Casualty'
AND UPPER (C.ClientName) LIKE '%LIMITED%'
AND CL.date > '31/12/2014'
AND CL.Date IS NULL
AND (TK.tkloc = 'loc1' OR TK.tkloc = 'loc2')`
or
`WHERE DPT.Department = 'Casualty'
AND UPPER (C.ClientName) LIKE '%LIMITED%'
AND CL.date > '31/12/2014'
AND CL.Date IS NULL
AND TK.tkloc IN ('loc1', 'loc2')`

Related

Find third largest quote ever created for each of the accounts in the EC1 area

Can anyone help I'm new to SQL and trying to figure out the below question see image for the table structure;
Question = Select account name, contact last name, case number, quote number, quote date and quote value for the f third-largest quote ever created for each of the accounts in the EC1 area
So far I got;
Select
a.accountname, cc.lastname, c.casenumber,
q.quotenumber, q.quotedate, q.quotevalue
from
TBL_Quote q
Left join
TBL_case c On q.caseid = c.caseid
Left join
tbl_contact cc On c.contactID = cc. contactID
Left join
tbl_account a On a.accountid = cc.accountid
Where
left(a.postcode, 3) like 'EC1'
and for the third:
SELECT TOP 1 value
FROM
(SELECT DISTINCT TOP 3 value
FROM tbl_quote
ORDER BY value DESC) a
ORDER BY value
I can't seem to combine the top 3 and the query is it best to overpartion by ?
I would suggest joins and a row-limiting clause:
select ac.accountName, co.lastName, ca.caseNumber, qu.quoteNumber
from tbl_account ac
inner join tbl_contact co on co.accountId = ac.accountId
inner join tbl_case ca on ca.contactId = co.contactId
inner join tbl_quote qu on qu.caseId = ca.quoteId
where ac.postcode like 'EC1%'
order by len(qu.value) desc
offset 2 rows fetch next 1 row only

How can i check if the value exists and return different values depending on the answer?

First let me explain the Query im using at the moment.
As an example this query returns the value '357 kg':
SELECT TOP 1
CONCAT(POCI.Value,' kg')
FROM
ProductionOrder PO
LEFT JOIN Product P ON P.ProductionOrderId = PO.ProductionOrderId
LEFT JOIN ProductionOrderConfiguration POC ON POC.ProductionOrderConfigurationId = PO.ProductionOrderConfigurationId
LEFT JOIN ProductionOrderConfigurationItem POCI ON POCI.ProductionOrderConfigurationId = POC.ProductionOrderConfigurationId
WHERE
P.ProductId = #ProductId# AND POCI.Name = 'C_VIKTA'
The problem is that sometimes the POCI.Name (C_VIKTA) doesnt exists in the records, so its value (POCI.Value) doesnt get returned.
So i want the following logic to work, and i know that it can be solved with an CASE and EXISTS, but i just dont get that to work..
The result I want is that IF the POCI.Value exists return CONCAT(POCI.Value,' kg') ELSE return 'N/A'. Anyone got any idea on how to solve this?
Let me know if theres something else u need to know in order to help me out!
BR,
Mik
I suggest you move AND POCI.Name = 'C_VIKTA' from where clause to your left join as shown below
SELECT TOP 1
case when POCI.Value is not null then CONCAT(POCI.Value,' kg') else '' end
FROM
ProductionOrder PO
LEFT JOIN Product P ON P.ProductionOrderId = PO.ProductionOrderId
LEFT JOIN ProductionOrderConfiguration POC ON POC.ProductionOrderConfigurationId = PO.ProductionOrderConfigurationId
LEFT JOIN ProductionOrderConfigurationItem POCI ON POCI.ProductionOrderConfigurationId = POC.ProductionOrderConfigurationId AND POCI.Name = 'C_VIKTA'
WHERE
P.ProductId = #ProductId#
I think the simplest way would be to drop CONCAT which handles nulls and then rely on is null. So your single select column would be
SELECT TOP 1 ISNULL(POCI.Value+' kg','N\A')
This way you would get a null for the first argument if POCI.Value is null and therefore return 'N\A'
this WHERE POCI.Name = 'C_VIKTA' breaks the left join
so move it up into the left join or make them all regular joins
if it only return one row then drop the top
+ behaves different than concat
SELECT ISNULL(POCI.Value +' kg','N\A')
FROM ProductionOrder PO
JOIN Product P
ON P.ProductionOrderId = PO.ProductionOrderId
JOIN ProductionOrderConfiguration POC
ON POC.ProductionOrderConfigurationId = PO.ProductionOrderConfigurationId
JOIN ProductionOrderConfigurationItem POCI
ON POCI.ProductionOrderConfigurationId = POC.ProductionOrderConfigurationId
WHERE POCI.Name = 'C_VIKTA'
AND P.ProductId = #ProductId#
why do you need ProductionOrderConfiguration POC ?
SELECT ISNULL(POCI.Value +' kg','N\A')
FROM ProductionOrder PO
JOIN Product P
ON P.ProductionOrderId = PO.ProductionOrderId
JOIN ProductionOrderConfigurationItem POCI
ON POCI.ProductionOrderConfigurationId = PO.ProductionOrderConfigurationId
WHERE POCI.Name = 'C_VIKTA'
AND P.ProductId = #ProductId#

Original column name from T-SQL query that yields columns AFTER the original column name was reclassified

I have a relatively standard sql query with several table joins and where clauses that all relate a loan after it has been reclassified to ORE (Other Real Estate Owned). I am trying to list the value of one of the ORIGINAL fields (category) that has been changed now that it is ORE.
Say the original category was 1 for 'Consumer' but once the loan goes to ORE, the category is a 12 which includes ALL original categories (1,2,3,4)
Therein lies the problem - I need to show the ORE loans for only say categories 1 & 2. Nothing I've tried works - I'm assuming because the where clause at the bottom of the query specifies that I need various fields that all tie to the ORE status but NOT to the original categories. I've tried subqueries (don;t work because they are 'above' the main query's where clause...
Any general guidance would be greatly appreciated. Here's the query and the subquery below it:
SELECT
A.ACCTNO
E.SNAME,
B.OREO_ID,
A.OREODATE,
GC.CATEGORY
FROM
DBO.LOAN_SYSTEM AS A
LEFT OUTER JOIN DBO.ORE AS B
ON A.OREO_ID = B.OREO_ID
LEFT OUTER JOIN DBO.LOAN_TITLE AS C
ON A.OREO_ID = C.OREO_ID AND C.SEQ = 1
LEFT OUTER JOIN (SELECT * FROM DBO.LOAN_FC WHERE ISDELETED = 0 AND ISDISMISSED IS NULL) AS D
ON A.OREO_ID = D.OREO_ID
LEFT OUTER JOIN DBO.TBL_GROUP_CODES GC
ON E.[GROUP] = GC.GROUP_CODE
WHERE
D.FC_ID IS NOT NULL AND C.FORECLOSUREDATE IS NOT NULL AND GC.CATEGORY IN (1,2) --DOESN'T WORK BECAUSE ONCE IN OREO = 12
AND
E.STATUS NOT IN (2,8)
--SUBQUERY GETS ORIGINAL CATEGORY
SELECT
B.ACCTNO, C.CATEGORY
FROM DBO.LOAN_SYSTEM A
LEFT OUTER JOIN DBO.LOAN_DAILY_INFO B
ON B.ACCTNO = A.ACCTNO
AND B.TYPE = A.TYPE
LEFT OUTER JOIN DBO.TBL_GROUP_CODES C
ON C.GROUP_CODE = B.[GROUP]
LEFT OUTER JOIN DBO.TBL_LOAN_TYPES D
ON D.TYPE = A.TYPE
WHERE B.STATUS NOT IN (2,8)
AND C.CATEGORY IN (1,2)
I'm not 100% sure what you're trying to do here.. but you might need to use EXISTS here.
SELECT A.ACCTNO,
E.SNAME,
B.OREO_ID,
A.OREODATE,
GC.CATEGORY
FROM DBO.LOAN_SYSTEM AS A
LEFT OUTER JOIN DBO.ORE AS B ON A.OREO_ID = B.OREO_ID
LEFT OUTER JOIN DBO.LOAN_TITLE AS C ON A.OREO_ID = C.OREO_ID
AND C.SEQ = 1
LEFT OUTER JOIN (SELECT * FROM DBO.LOAN_FC WHERE ISDELETED = 0 AND ISDISMISSED IS NULL
) AS D ON A.OREO_ID = D.OREO_ID
LEFT OUTER JOIN DBO.TBL_GROUP_CODES GC ON D.[GROUP] = GC.GROUP_CODE
WHERE D.FC_ID IS NOT NULL
AND C.FORECLOSUREDATE IS NOT NULL
AND EXISTS (
SELECT 1
FROM DBO.LOAN_DAILY_INFO F
JOIN DBO.TBL_GROUP_CODES G ON G.GROUP_CODE = F.[GROUP]
WHERE F.STATUS NOT IN (2,8)
AND G.CATEGORY IN (1,2)
AND F.ACCTNO = A.ACCTNO
AND F.TYPE = A.TYPE
)
AND D.STATUS NOT IN (2,8)

How to join one select with another when the first one not always returns a value for specific row?

I have a complex query to retrieve some results:
EDITED QUERY (added the UNION ALL):
SELECT t.*
FROM (
SELECT
dbo.Intervencao.INT_Processo, analista,
ETS.ETS_Sigla, ATC.ATC_Sigla, PAT.PAT_Sigla, dbo.Assunto.SNT_Peso,
CASE
WHEN ETS.ETS_Sigla = 'PE' AND (PAT.PAT_Sigla = 'LIB' OR PAT.PAT_Sigla = 'LBR') THEN (0.3*SNT_Peso)
WHEN ETS.ETS_Sigla = 'CD' THEN (0.3*SNT_Peso)*0.3
ELSE SNT_Peso
END AS PESOAREA,
CASE
WHEN a.max_TEA_FimTarefa IS NULL THEN a.max_TEA_InicioTarefa
ELSE a.max_TEA_FimTarefa
END AS DATA_INICIO_TERMINO,
ROW_NUMBER() OVER (PARTITION BY ATC.ATC_Sigla, a.SRV_Id ORDER BY TEA_FimTarefa DESC) AS seqnum
FROM dbo.Tarefa AS t
INNER JOIN (
SELECT
MAX(dbo.TarefaEtapaAreaTecnica.TEA_InicioTarefa) AS max_TEA_InicioTarefa,
MAX (dbo.TarefaEtapaAreaTecnica.TEA_FimTarefa) AS max_TEA_FimTarefa,
dbo.Pessoa.PFJ_Descri AS analista, dbo.AreaTecnica.ATC_Id, dbo.Tarefa.SRV_Id
FROM dbo.TarefaEtapaAreaTecnica
LEFT JOIN dbo.Tarefa ON dbo.TarefaEtapaAreaTecnica.TRF_Id = dbo.Tarefa.TRF_Id
LEFT JOIN dbo.AreaTecnica ON dbo.TarefaEtapaAreaTecnica.ATC_Id = dbo.AreaTecnica.ATC_Id
LEFT JOIN dbo.ServicoAreaTecnica ON dbo.TarefaEtapaAreaTecnica.ATC_Id = dbo.ServicoAreaTecnica.ATC_Id
AND dbo.Tarefa.SRV_Id = dbo.ServicoAreaTecnica.SRV_Id
INNER JOIN dbo.Pessoa ON dbo.Pessoa.PFJ_Id = dbo.ServicoAreaTecnica.PFJ_Id_Analista
GROUP BY dbo.AreaTecnica.ATC_Id, dbo.Tarefa.SRV_Id, dbo.Pessoa.PFJ_Descri
) AS a ON t.SRV_Id = a.SRV_Id
INNER JOIN dbo.TarefaEtapaAreaTecnica AS TarefaEtapaAreaTecnica_1 ON
t.TRF_Id = TarefaEtapaAreaTecnica_1.TRF_Id
AND a.ATC_Id = TarefaEtapaAreaTecnica_1.ATC_Id
AND a.max_TEA_InicioTarefa = TarefaEtapaAreaTecnica_1.TEA_InicioTarefa
LEFT JOIN AreaTecnica ATC ON TarefaEtapaAreaTecnica_1.ATC_Id = ATC.ATC_Id
LEFT JOIN Etapa ETS ON TarefaEtapaAreaTecnica_1.ETS_Id = ETS.ETS_Id
LEFT JOIN ParecerTipo PAT ON TarefaEtapaAreaTecnica_1.PAT_Id = PAT.PAT_Id
LEFT OUTER JOIN dbo.Servico ON a.SRV_Id = dbo.Servico.SRV_Id
INNER JOIN dbo.Intervencao ON dbo.Servico.INT_Id = dbo.Intervencao.INT_Id
LEFT JOIN dbo.Assunto ON dbo.Servico.SNT_Id = dbo.Assunto.SNT_Id
) t
The result is following:
It works good, the problem is that I was asked that if when a row is not present on this query, it must contain values from another table (ServicoAreaTecnica), so I got this query for the other table based on crucial information of the first query. So if I UNION ALL I get this:
Query1 +
UNION ALL
SELECT INN.INT_Processo,
PES.PFJ_Descri,
NULL, --ETS.ETS_Sigla,
ART.ATC_Sigla,
NULL ,--PAT.PAT_Sigla,
ASS.SNT_Peso,
NULL, --PESOAREA
NULL, --DATA_INICIO_TERMINO
NULL --seqnum
FROM dbo.ServicoAreaTecnica AS SAT
INNER JOIN dbo.AreaTecnica AS ART ON ART.ATC_Id = SAT.ATC_Id
INNER JOIN dbo.Servico AS SER ON SER.SRV_Id = SAT.SRV_Id
INNER JOIN dbo.Assunto AS ASS ON ASS.SNT_Id = SER.SNT_Id
INNER JOIN dbo.Intervencao AS INN ON INN.INT_Id = SER.INT_Id
INNER JOIN dbo.Pessoa AS PES ON PES.PFJ_Id = SAT.PFJ_Id_Analista
The result is following:
So what I want to do is to remove row number 1 because row number 2 exists on the first query, I think I got it explained better this time. The result should be only row number 1, row number 2 would appear only if query 1 doesn't retrieve a row for that particular INN.INT_Processo.
Thanks!
Ok, there are two ways to reduce your record set. Given that you've already written the code to produce the table with the extra rows, it might be easiest to just add code to reduce that:
Select * from
(Select *
, Row_Number() over
(partition by IntProcesso, Analista order by ISNULL(seqnum, 0) desc) as RN
from MyResults) a
where RN = 1
This will assign row_number 1 to any rows that came from your first query, or to any rows from the second query that do not have matches in the first query, then filter out extra rows.
You could also use outer joins with isnull or coalesce, as others have suggested. Something like this:
Select ISNULL(a.IntProcesso, b.IntProcesso) as IntProcesso
, ISNULL(a.Analista, b.Analista) as Analista
, ISNULL(a.ETSsigla, b.ETSsigla) as ETSsigla
[repeat for the rest of your columns]
from Table1 a
full outer join Table2 b
on a.IntProcesso = b.IntProcesso and a.Analista = b.Analista
Your code is hard to read, because of the lengthy names of everything (and to be honest, the fact that they're in a language I don't speak also makes it a lot harder).
But how about: replacing your INNER JOINs with LEFT JOINs, adding more LEFT JOINs to draw in the alternative tables, and introducing ISNULL clauses for each variable you want in the results?
If you do something like ... Query1 Right Join Query2 On ... that should get only the rows in Query2 that don't appear in Query 1.

SQL Server left join with conditionals not giving me results I want

Query first, and then question:
SELECT DISTINCT p.postID, p.postGUID, p.postTitle, p.postTypeID, p.sequence, m.firstname, m.lastname, pt.postTypeName, mc.acceptRejectDate
FROM post p
INNER JOIN member m ON p.memberGUID = m.memberGUID
INNER JOIN postType pt ON p.postTypeID = pt.postTypeID
LEFT JOIN masterClass mc ON (p.postGUID = mc.postGUID AND mc.isMemberPrivate = 0 AND mc.status = 2 AND mc.acceptRejectDate IS NOT NULL)
WHERE p.postTitle LIKE '%five%'
AND p.isActive = 1
ORDER BY p.postTypeID, p.sequence, mc.acceptRejectDate
What I'm trying to do here is grab all results from the "posts" table that have isActive = 1 and the title includes "five." Easy enough.
Some of the results also have an association to the masterClass table. For those results I only want to include them if isMemberPrivate is zero, status is 2, and there is an acceptRejectDate.
I thought this would be easy enough, but when I run the query I get results including some posts that don't meet the master class join criteria. And, there are a few results that are displaying as having null values but clearly don't when I look at the raw data.
Is there anything in this query that looks wrong and would cause my results to be incorrect?
From reading your question, I believe you want to include all results that either have no record in the masterClass table, or do have records in the masterClass table that meet your criteria. If you move your criteria down to the WHERE section, and add a check for records that did not match anything in the masterClass table, you should get what you want.
SELECT DISTINCT p.postID, p.postGUID, p.postTitle, p.postTypeID, p.sequence, m.firstname, m.lastname, pt.postTypeName, mc.acceptRejectDate
FROM post p
INNER JOIN member m ON p.memberGUID = m.memberGUID
INNER JOIN postType pt ON p.postTypeID = pt.postTypeID
LEFT JOIN masterClass mc ON p.postGUID = mc.postGUID
WHERE p.postTitle LIKE '%five%'
AND p.isActive = 1
AND ( mc.postGUID is NULL OR
(mc.isMemberPrivate = 0 AND mc.status = 2 AND mc.acceptRejectDate IS NOT NULL)
)
ORDER BY p.postTypeID, p.sequence, mc.acceptRejectDate
Edit: Changed field looking for NULLs from mc.acceptRejectDate to mc.postGUID
Try this to clearly separate JOIN and filter conditions
...
LEFT JOIN
(
SELECT postGUID, acceptRejectDate
FROM masterClass
WHERE isMemberPrivate = 0 AND status = 2 AND acceptRejectDate IS NOT NULL
) mc ON p.postGUID = mc.postGUID
...

Resources