Why IsNull it doesnt worK? - sql-server

I'm trying to run this query and when it doesnt find value i need to take result 0.neither my return is null or empty.
select top(1)
ISNULL(CONVERT(DECIMAL(10,2),a.VatValue),0) as VatC
from VatCodes a
join
InventoryMainGroupItems b on a.VatcodeID = b.VatCodeID
join InventoryTransTemp c on c.CategoryID = b.MainGroupItemID
where
c.TrnDocumentID = '409'
and
a.VatcodeID = 3
Now my column returns emtpy.
My desired result should be 0

I could be wrong but I think the InventoryMainGroupItems has rows with a null in the VatCodeId column.
If this is the case then you can amend your slightly like so
select top(1)
ISNULL(CONVERT(DECIMAL(10,2),a.VatValue),0) as VatC
from InventoryMainGroupItems b
LEFT join
VatCodes a on a.VatcodeID = b.VatCodeID
INNER JOIN InventoryTransTemp c on c.CategoryID = b.MainGroupItemID
where
c.TrnDocumentID = '409'
and
a.VatcodeID = 3

There are at least 2 possibilities.
No rows meet the conditions as specified in the joins and where clause. Also, I'd start using explicit joins
The column VatValue doesnt' contain any NULL values, but instead contains empty spaces which isn't the same as NULL
Try to use replace to test for the empty string.
select top(1)
ISNULL(REPLCACE(CONVERT(DECIMAL(10,2),a.VatValue),'',0),0) as VatC
from VatCodes a
join
InventoryMainGroupItems b on a.VatcodeID = b.VatCodeID
join InventoryTransTemp c on c.CategoryID = b.MainGroupItemID
where
c.TrnDocumentID = '409'
and
a.VatcodeID = 3
If that doesn't work, your condition isn't returning any rows. Here's a way to prove that... this shouldn't return any rows....
select top(1)
a.VatValue as VatC
from VatCodes a
join
InventoryMainGroupItems b on a.VatcodeID = b.VatCodeID
join InventoryTransTemp c on c.CategoryID = b.MainGroupItemID
where
c.TrnDocumentID = '409'
and
a.VatcodeID = 3

Related

How to use inner join and left join for two tables in same query using T-SQL

Given two tables:
tblBase - database table (code_no, empid)
#type_temp is a temporary user defined table which will come from vb.net frontend (code_no, name)
Firstly I need to get code_no which are in #type_temp and not in tblBase.
Query:
select
t.code_no, 'Non-existing' as Remark
from
#type_temp t
left join
tblBase b on t.code_no = b.code_no
where
b.code_no is null
Next I need to get all code_no that have empid = 1.
Query :
select
t.code_no, 'Existing' as Remark
from
#type_temp t
inner join
tblBase b on t.code_no = b.code_no
where
b.empid = 1
I need to use both these queries together.
Currently I'm using union to club the two.
select
t.code_no, 'Non-existing' as Remark
from
#type_temp t
left join
tblBase b on t.code_no = b.code_no
where
b.code_no is null
union
select
t.code_no, 'Existing' as Remark
from
#type_temp t
inner join
tblBase b on t.code_no = b.code_no
where
b.empid = 1
I do not want union here. Any other alternative possible?
Does this work for you?
SELECT type_temp.code_no
, CASE WHEN tblBase.code_no IS NULL THEN 'Non-existing' ELSE 'Existing' END AS Remark
FROM #type_temp AS type_temp
LEFT
JOIN tblBase
ON tblBase.code_no = type_temp.code_no
WHERE tblBase.empid = 1
OR tblBase.code_no IS NULL
;
An even better option than #gvee's answer, is to put the conditions into the ON clause
SELECT
type_temp.code_no,
CASE WHEN tblBase.code_no IS NULL THEN 'Non-existing' ELSE 'Existing' END AS Remark
FROM #type_temp AS type_temp
LEFT JOIN tblBase ON tblBase.code_no = type_temp.code_no
AND tblBase.empid = 1;
This is likely to be more performant, as the join is pre-filtered.

Multiple Nested Inner Joins: not all records are shown

I have difficulty joining two tables that look like the following:
The main table PMEOBJECT which has a unique key named OBJECTID and
has in total 12768 rows.
Then I want to join PMEOBJECTVALIDITY on it which has an n:1 relationship with PMEOBJECT, since it has more rows,
because it saves the changes over time of PMEOBJECT (i.e. when a certain object is not
valid anymore), this one has 12789 rows (meaning only 21 objects
changed over time). However, I only want to have the current last
VALIDFROM date shown in the query. This all works fine.
Then the trouble starts when I want to join PMEOBJECTDIMENSION, which has an
n:1 relationship with PMEOBJECTVALIDITY and has 36737 rows in total.
SELECT
PMEOBJECT.OBJECTID
,PMEOBJECTVALIDITY.VALIDFROM
,PMEOBJECTDIMENSION.DIMENSION2_
FROM PMEOBJECT
LEFT JOIN PMEOBJECTVALIDITY
ON PMEOBJECTVALIDITY.OBJECTID = PMEOBJECT.OBJECTID
AND PMEOBJECTVALIDITY.DATAAREAID = PMEOBJECT.DATAAREAID
INNER JOIN(
SELECT
OBJECTID,
MAX(VALIDFROM) AS NEWFROMDATE,
MAX(VALIDTO) AS NEWTODATE
FROM PMEOBJECTVALIDITY B
GROUP BY OBJECTID
) B
ON PMEOBJECTVALIDITY.OBJECTID = B.OBJECTID
AND PMEOBJECTVALIDITY.VALIDFROM = B.NEWFROMDATE
LEFT JOIN PMEOBJECTDIMENSION
ON PMEOBJECTDIMENSION.OBJECTVALIDITYID = PMEOBJECTVALIDITY.RECID
AND PMEOBJECTDIMENSION.DATAAREAID = PMEOBJECTVALIDITY.DATAAREAID
INNER JOIN(
SELECT
OBJECTVALIDITYID,
MAX(VALIDFROM) AS NEWFROMDATE_2
FROM PMEOBJECTDIMENSION C
GROUP BY OBJECTVALIDITYID
) C
ON PMEOBJECTDIMENSION.OBJECTVALIDITYID = C.OBJECTVALIDITYID
AND PMEOBJECTDIMENSION.VALIDFROM = C.NEWFROMDATE_2
Results in query per step:
SELECT PMEOBJECT: 12768 rows
LEFT JOIN PMEVALIDITY: 12789 rows
INNER JOIN PMEVALIDITY: 12768 rows
LEFT JOIN PMEOBJECTDIMENSION: 36737 rows
INNER JOIN PMEOBJECTDIMENSION: 12729 rows
I want the end result again to have the same 12768 rows, I don't want any ObjectId to be left out.
What am I missing here?
Kind regards,
Igor
Following might help:
from PMEOBJECTDIMENSION onwards:
LEFT JOIN (SELECT PMEOBJECTDIMENSION.OBJECTVALIDITYID, PMEOBJECTDIMENSION.DATAAREAID
FROM PMEOBJECTDIMENSION
INNER JOIN(SELECT OBJECTVALIDITYID, MAX(VALIDFROM) AS NEWFROMDATE_2
FROM PMEOBJECTDIMENSION C
GROUP BY OBJECTVALIDITYID
) C
ON PMEOBJECTDIMENSION.OBJECTVALIDITYID = C.OBJECTVALIDITYID
AND PMEOBJECTDIMENSION.VALIDFROM = C.NEWFROMDATE_2
)X
ON X.OBJECTVALIDITYID = PMEOBJECTVALIDITY.RECID
AND X.DATAAREAID = PMEOBJECTVALIDITY.DATAAREAID
and select the distinct records if duplicates present.
The INNER JOINs are filtering out records- what you want is that the LEFT JOIN table (PMEOBJECTVALIDITY and PMEOBJECTDIMENSION) should only include records that have at least a match on the INNER JOIN queries (alias B and C). You can accomplish this with by nesting the INNER JOIN with the LEFT JOIN, generally done as follows:
SELECT *
FROM A
LEFT JOIN B
INNER JOIN C
ON B.ID = C.BID
ON A.ID = B.AID
Now B is INNER JOINed on C and will only contain records that have a match in C, but will preserve the LEFT JOIN not remove any records from A.
In your case, you can simply move the ON clause from the LEFT JOIN to the end of the following INNER JOIN.
SELECT
PMEOBJECT.OBJECTID
,PMEOBJECTVALIDITY.VALIDFROM
,PMEOBJECTDIMENSION.DIMENSION2_
FROM PMEOBJECT
LEFT JOIN PMEOBJECTVALIDITY
INNER JOIN(
SELECT
OBJECTID,
MAX(VALIDFROM) AS NEWFROMDATE,
MAX(VALIDTO) AS NEWTODATE
FROM PMEOBJECTVALIDITY B
GROUP BY OBJECTID
) B
ON PMEOBJECTVALIDITY.OBJECTID = B.OBJECTID
AND PMEOBJECTVALIDITY.VALIDFROM = B.NEWFROMDATE
ON PMEOBJECTVALIDITY.OBJECTID = PMEOBJECT.OBJECTID
AND PMEOBJECTVALIDITY.DATAAREAID = PMEOBJECT.DATAAREAID --here it is!
LEFT JOIN PMEOBJECTDIMENSION
INNER JOIN(
SELECT
OBJECTVALIDITYID,
MAX(VALIDFROM) AS NEWFROMDATE_2
FROM PMEOBJECTDIMENSION C
GROUP BY OBJECTVALIDITYID
) C
ON PMEOBJECTDIMENSION.OBJECTVALIDITYID = C.OBJECTVALIDITYID
AND PMEOBJECTDIMENSION.VALIDFROM = C.NEWFROMDATE_2
ON PMEOBJECTDIMENSION.OBJECTVALIDITYID = PMEOBJECTVALIDITY.RECID
AND PMEOBJECTDIMENSION.DATAAREAID = PMEOBJECTVALIDITY.DATAAREAID --I'm here

Count function returns empty record set need it to return 0 instead

I have this query...
SELECT COUNT(*) AS dupes
FROM documents d JOIN mv_compgift g ON g.documentId = d.id
JOIN mv_donorid di ON di.documentId = d.id
JOIN mv_appealcode ac ON ac.documentId = d.id
GROUP BY di.value,ac.value,d.dateDeleted
HAVING COUNT(*) > 1
AND g.value = 'Y'
AND d.dateDeleted IS NULL
AND di.value = '0621839010'
AND ac.value = 'AD62Q'
I need it to show a 0 when I have an empty record-set.
I have looked and tried different functions like coalesce but nothing works...please help. thanks
DECLARE #Count INT
SELECT #Count=COUNT(*) AS dupes
FROM documents d JOIN mv_compgift g ON g.documentId = d.id
JOIN mv_donorid di ON di.documentId = d.id
JOIN mv_appealcode ac ON ac.documentId = d.id
GROUP BY di.value,ac.value,d.dateDeleted
HAVING COUNT(*) > 1
AND g.value = 'Y'
AND d.dateDeleted IS NULL
AND di.value = '0621839010'
AND ac.value = 'AD62Q'
SELECT ISNULL(#Count,0) AS [dupes]
SELECT
COUNT(*), -- raw value
CASE COUNT(*)
WHEN 1 THEN 'OK' WHEN 0 THEN 'NOTHING' ELSE 'DUPS'
END as HasDups -- translated value
FROM documents d JOIN mv_compgift g ON g.documentId = d.id
JOIN mv_donorid di ON di.documentId = d.id
JOIN mv_appealcode ac ON ac.documentId = d.id
WHERE g.value = 'Y' AND d.dateDeleted IS NULL
AND di.value = '0621839010' AND ac.value = 'AD62Q'
Your HAVING condition was eliminating groups that didn't have dups. There was no way to ever get a zero back.
Also I'm surprised there wasn't an error on the g.value filter. All those conditions appear to belong in WHERE rather than HAVING anyway.

SQL Server 2005 - WHERE NOT EXISTS and a complicated script inside of the NOT EXISTS

Script objective: get a list of numbers from a list where the numbers don't show up in another list.
The complications: the other list of numbers can only be obtained via a complicated script - and for some reason I'm getting no results when I KNOW there should be; since the first list will contain ALL the numbers and the second list of numbers will only contain some numbers; so I should be getting some results.
The script I have written (censored)
SELECT A.Number
FROM sometable AS A
INNER JOIN othertable AS B
ON A.Data = B.Data
INNER JOIN othertable2 AS C
ON B.Data = C.Data
INNER JOIN othertable3 AS D
ON C.Data = D.Data
WHERE D.Data = 'int'
AND NOT EXISTS (SELECT DISTINCT A.Number
FROM sometable AS C
anothertable AS B
ON C.Data = B.Data
INNER JOIN anothertable AS E
ON B.Data = E.Data
INNER JOIN anothertable AS A
ON E.Data = A.Data
CROSS apply (SELECT DG.Data
FROM atable AS DG
WHERE B.Data = DG.Data) D
WHERE D.Data IN ( 'int', 'int', 'int', 'int' ))
If I run the part1 (before the non exist) it works fine
If I run part2 (the data within the non exist) it also works fine - with different, and less results (containing numbers from part1)
But together they don't. So I need to know how to do this if not exist is not what I need to use?
Your Query is working as it should. Since there are some rows exists in your sub query the outer query didn't produce any result but that is not the right way to complete your objective
Your Objective
Get a list of numbers from a list where the numbers don't show up in another list.
can be done in two ways.
Using Not Exists
SELECT A.Number
FROM sometable AS A
INNER JOIN othertable AS B
ON A.Data = B.Data
INNER JOIN othertable2 AS C
ON B.Data = C.Data
INNER JOIN othertable3 AS D
ON C.Data = D.Data
WHERE D.Data = 'int'
AND NOT EXISTS (SELECT 1
FROM sometable AS CC
INNER JOIN anothertable AS BB
ON Cc.Data = BB.Data
INNER JOIN anothertable AS EE
ON BB.Data = EE.Data
INNER JOIN anothertable AS AA
ON EE.Data = AA.Data
CROSS apply (SELECT DG.Data
FROM atable AS DG
WHERE BB.Data = DG.Data) DD
WHERE DD.Data IN ( 'int', 'int', 'int', 'int' )
AND aa.number = a.number)
Or by using Not IN
SELECT A.Number
FROM sometable AS A
INNER JOIN othertable AS B
ON A.Data = B.Data
INNER JOIN othertable2 AS C
ON B.Data = C.Data
INNER JOIN othertable3 AS D
ON C.Data = D.Data
WHERE D.Data = 'int'
AND A.Number NOT IN (SELECT AA.number
FROM sometable AS CC
INNER JOIN anothertable AS BB
ON Cc.Data = BB.Data
INNER JOIN anothertable AS EE
ON BB.Data = EE.Data
INNER JOIN anothertable AS AA
ON EE.Data = AA.Data
CROSS apply (SELECT DG.Data
FROM atable AS DG
WHERE BB.Data = DG.Data) DD
WHERE DD.Data IN ( 'int', 'int', 'int', 'int' )
AND aa.number = a.number)
You said that the subquery, run independently, produces results. Therefore, when run in the NOT EXISTS clause, it will always produce results and therefore the clause will always be false.
My guess is that what you meant is more along the lines of WHERE A.Number NOT IN ( ... )

SQL Server AVG and Excel AVERAGE producing different results?

I'm trying to show averages on SQL server, but when I test the data in Excel the results are not the same, there must be something obvious I am missing.
Here is the code and results from SQL server:
SELECT DISTINCT
d.d_reference + ' - ' + d.d_name AS Faculty,
AVG(sub.GroupSize) AS FacultyAverage
FROM
unitesnapshot.dbo.capd_register r
INNER JOIN unitesnapshot.dbo.capd_studentregister sr ON sr.sr_register = r.r_id
INNER JOIN unitesnapshot.dbo.capd_activity a ON a.a_register = r.r_id
INNER JOIN unitesnapshot.dbo.capd_moduleactivity ma ON ma.ma_activity = a.a_id
INNER JOIN unitesnapshot.dbo.capd_module m ON m.m_id = ma.ma_activitymodule
INNER JOIN unitesnapshot.dbo.capd_department d ON d.d_id = m.m_moduledept
INNER JOIN unitesnapshot.dbo.capd_section sec ON sec.s_id = m.m_modulesection
INNER JOIN (SELECT
r.r_reference,
COUNT(DISTINCT s.s_studentreference) AS GroupSize
FROM
unitesnapshot.dbo.capd_student s
INNER JOIN unitesnapshot.dbo.capd_person p ON p.p_id = s.s_id
INNER JOIN unitesnapshot.dbo.capd_studentregister sr ON sr.sr_student = p.p_id
INNER JOIN unitesnapshot.dbo.capd_register r ON r.r_id = sr.sr_register
GROUP BY
r.r_reference) sub ON sub.r_reference = r.r_reference
WHERE
SUBSTRING(r.r_reference,4,2) = '12' AND
d.d_reference = '730'
GROUP BY
d.d_reference,
d.d_name
Here is the results in Excel:
Thanks
Try this for fun:
select avg(a)
from
(values(1),(2),(3),(4)) x(a);
avg(a)
-------
2
AVG() returns the same datatype as the base column. If your columns are of type int, then the result will be truncated to an int as well. The below returns the "correct" result.
select avg(cast(a as decimal(10,5)))
from
(values(1),(2),(3),(4)) x(a);
result
--------
2.5
The discrepancy you are showing (24 vs 19.50484) will most likely involve another error in conjunction with this. For example, to check that you are summing up the same data in Excel as in SQL Server, dump this result into Excel and sum it up. If it doesn't match what you currently believe is the Excel equivalent of the SQL Server data, line the columns up and check they have the same number of rows. Then sort each column individually by value ASCENDING and compare again.
SELECT d.d_name, sub.GroupSize AS FacultyAverage
FROM unitesnapshot.dbo.capd_register r
INNER JOIN unitesnapshot.dbo.capd_studentregister sr ON sr.sr_register = r.r_id
INNER JOIN unitesnapshot.dbo.capd_activity a ON a.a_register = r.r_id
INNER JOIN unitesnapshot.dbo.capd_moduleactivity ma ON ma.ma_activity = a.a_id
INNER JOIN unitesnapshot.dbo.capd_module m ON m.m_id = ma.ma_activitymodule
INNER JOIN unitesnapshot.dbo.capd_department d ON d.d_id = m.m_moduledept
INNER JOIN unitesnapshot.dbo.capd_section sec ON sec.s_id = m.m_modulesection
INNER JOIN (SELECT r.r_reference,
COUNT(DISTINCT s.s_studentreference) AS GroupSize
FROM unitesnapshot.dbo.capd_student s
INNER JOIN unitesnapshot.dbo.capd_person p ON p.p_id = s.s_id
INNER JOIN unitesnapshot.dbo.capd_studentregister sr ON sr.sr_student = p.p_id
INNER JOIN unitesnapshot.dbo.capd_register r ON r.r_id = sr.sr_register
GROUP BY r.r_reference) sub ON sub.r_reference = r.r_reference
WHERE SUBSTRING(r.r_reference,4,2) = '12' AND d.d_reference = '730'
ORDER BY d.d_name

Resources