Sum when field does not exist - sql

I have the following table:
create table #tbl
(
[type] varchar(20),
[qty] int
)
insert into #tbl values ('Type A', 10)
insert into #tbl values ('Type A', 15)
insert into #tbl values ('Type B', 5)
insert into #tbl values ('Type B', 8)
Now I want to display the total qty of each individual 'type':
select
isnull([type], 'Other') as [type],
sum(case
when [type] = 'Type A' then qty
when [type] = 'Type B' then qty
when [type] = 'Type C' then qty
else 0
end) as [total]
from #tbl
where [type] in ('Type A', 'Type B', 'Type C')
group by [type]
It correctly sums up each 'type'. Here's the result:
type total
--------------
Type A 25
Type B 13
But I want Type C to be included in the result as well (with a total qty of 0).
type total
--------------
Type A 25
Type B 13
Type C 0
How can I accomplish that?
I'm using MS SQL Server 2005.

The problem is that you don't have Type C in the table so there is nothing to return. One way you could this is to create a derived table with all of the values that you want include and then LEFT JOIN your table:
select d.type,
sum(coalesce(t.qty, 0)) Total
from
(
select 'Type A' type union all
select 'Type B' type union all
select 'Type C' type
) d
left join tbl t
on d.type = t.type
group by d.type;
See SQL Fiddle with Demo

You will need a table containing the list of types you want to report and do a left join on that. Something like the following:
create table #tbl
(
[type] varchar(20),
[qty] int
);
insert into #tbl values ('Type A', 10)
insert into #tbl values ('Type A', 15)
insert into #tbl values ('Type B', 5)
insert into #tbl values ('Type B', 8)
create table #types ( [type] varchar(20) );
insert into #types values ('Type A' );
insert into #types values ('Type B' );
insert into #types values ('Type C' );
select t.[type], [Total] = IsNull(t.[total], 0)
from ( select [type] = IsNull(t.[Type], 'Other')
, [total] = sum(tbl.[qty])
from #types t
left
join #tbl tbl ON tbl.[type] = t.type
group
by t.[type]
) as t
;
The sub-query is necessary to convert the NULL sums to zero.

Also you can get the result by applying both the UNPIVOT and the PIVOT operators.
SELECT type, qty
FROM(
SELECT COALESCE([Type A], 0) AS [Type A],
COALESCE([Type B], 0) AS [Type B],
COALESCE([Type C], 0) AS [Type C]
FROM (
SELECT [type], [qty]
FROM #tbl
) x
PIVOT (
SUM([qty]) FOR [type] IN([Type A], [Type B], [Type C])
) p
)x
UNPIVOT (
[qty] FOR [type] IN([Type A], [Type B], [Type C])
) u
Demo on SQLFiddle

Related

SQL Query Dynamically get columns depending on mapping

I am stuck on an issue. I am trying to create a select which returns information depending on the Rules Mapping table. The Rules table tells us where (TableName.ColumnName) value should come from. I have simplified the problem by just creating table variables to find a solution.
I have 3 tables set up.
#TableA which contains the Main_ID. First Table.
#TableB which contains more information for the Main_ID. Second table.
#Rules is the mapping table. It has headers for what the final select should have and also tells us where the the data should come from (What table and column).
The final expected result I am trying to achieve is this with the above rules is:
As you can see, I will have 3 columns in total with 3 rows (as I have 3 Main_ID). Data differs depending on the #Rules table. For example, Header C for Main_ID 3 is showing "Address C" as the rule mapping for Header C Main_ID 3 was "#TableB.Address" which means get the information from table #TableB and column Address.
Here is my code for the table set up:
DECLARE #TableA AS TABLE
(
Main_ID INT IDENTITY(1, 1) ,
Name VARCHAR(100)
)
INSERT INTO #TableA
VALUES ('Name A'), ('Name B'), ('Name C')
DECLARE #TableB AS TABLE
(
Secondary_ID INT IDENTITY(1, 1) ,
Main_ID INT ,
Address VARCHAR(100)
)
INSERT INTO #TableB
VALUES (1, 'Address A'), (2, 'Address B'), (3, 'Address C')
DECLARE #Rules AS TABLE
(
Rule_ID INT IDENTITY(1, 1) ,
Main_ID INT ,
Header_Name VARCHAR(100) ,
Obtain_From VARCHAR(100)
)
INSERT INTO #Rules
VALUES
-- Main_ID 1 AND 2 set up same but third one wants data from a different place.
(1, 'Header A', '#TableA.Main_ID'), (1, 'Header B', '#TableB.Address'), (1, 'Header C', '#TableA.Name'),
(2, 'Header A', '#TableA.Main_ID'), (2, 'Header B', '#TableB.Address'), (2, 'Header C', '#TableA.Name'),
(3, 'Header A', '#TableA.Main_ID'), (3, 'Header B', '#TableA.Name'), (3, 'Header C', '#TableB.Address')
SELECT * FROM #TableA
SELECT * FROM #TableB
SELECT * FROM #Rules
/*
Final result set should be:
Header A Header B Header C
1 Address A Name A
2 Address B Name B
3 Name C Address C
*/
What I have tried so far is joining the table together but there are too many rows.
Any ideas how I can achieve the final expected result?
There is a two way to do it.
The first way is static and easy.
You can use CASE expression for your mapping like that:
SELECT
[Header A] = CASE r_headera.Obtain_From WHEN '#TableA.Main_ID' THEN CAST(a.Main_ID AS NVARCHAR(100)) WHEN '#TableA.Name' THEN CAST(a.Name AS NVARCHAR(100)) WHEN '#TableB.Address' THEN CAST(b.Address AS NVARCHAR(100)) END,
[Header B] = CASE r_headerb.Obtain_From WHEN '#TableA.Main_ID' THEN CAST(a.Main_ID AS NVARCHAR(100)) WHEN '#TableA.Name' THEN CAST(a.Name AS NVARCHAR(100)) WHEN '#TableB.Address' THEN CAST(b.Address AS NVARCHAR(100)) END,
[Header C] = CASE r_headerc.Obtain_From WHEN '#TableA.Main_ID' THEN CAST(a.Main_ID AS NVARCHAR(100)) WHEN '#TableA.Name' THEN CAST(a.Name AS NVARCHAR(100)) WHEN '#TableB.Address' THEN CAST(b.Address AS NVARCHAR(100)) END
FROM
#TableA AS a
LEFT JOIN #TableB AS b ON b.Main_ID = a.Main_ID
LEFT JOIN #Rules AS r_headera ON r_headera.Main_ID = a.Main_ID AND r_headera.Header_Name = 'Header A'
LEFT JOIN #Rules AS r_headerb ON r_headerb.Main_ID = a.Main_ID AND r_headerb.Header_Name = 'Header B'
LEFT JOIN #Rules AS r_headerc ON r_headerc.Main_ID = a.Main_ID AND r_headerc.Header_Name = 'Header C'
Otherwise, you can use other structs such as Table Value Constructor, PIVOT, OUTER APPLY etc.
The result:
Header A
Header B
Header C
1
Address A
Name A
2
Address B
Name B
3
Name C
Address C
And the second way is Dynamic SQL with sp_executesql .
If you need help with that, I can prepare an example for you.

Want to compare 4 different columns with the result of CTE

I have created a CTE (common table Expression) as follows:
DECLARE #N VARCHAR(100)
WITH CAT_NAM AS (
SELECT ID, NAME
FROM TABLE1
WHERE YEAR(DATE) = YEAR(GETDATE())
)
SELECT #N = STUFF((
SELECT ','''+ NAME+''''
FROM CAT_NAM
WHERE ID IN (20,23,25,30,37)
FOR XML PATH ('')
),1,1,'')
The result of above CTE is 'A','B','C','D','F'
Now I need to check 4 different columns CAT_NAM_1,CAT_NAM_2,CAT_NAM_3,CAT_NAM_4 in the result of CTE and form it as one column like follow:
Select
case when CAT_NAM_1 in (#N) then CAT_NAM_1
when CAT_NAM_2 in (#N) then CAT_NAM_2
when CAT_NAM_3 in (#N) then CAT_NAM_3
when CAT_NAM_4 in (#N) then CAT_NAM_4
end as CAT
from table2
When I'm trying to do the above getting error please help me to do.
If my approach is wrong help me with right one.
I am not exactly sure what you are trying to do, but if I understand the following script shows one possible technique. I have created some table variables to mimic the data you presented and then wrote a SELECT statement to do what I think you asked (but I am not sure).
DECLARE #TABLE1 AS TABLE (
ID INT NOT NULL,
[NAME] VARCHAR(10) NOT NULL,
[DATE] DATE NOT NULL
);
INSERT INTO #TABLE1(ID,[NAME],[DATE])
VALUES (20, 'A', '2021-01-01'), (23, 'B', '2021-02-01'),
(25, 'C', '2021-03-01'),(30, 'D', '2021-04-01'),
(37, 'E', '2021-05-01'),(40, 'F', '2021-06-01');
DECLARE #TABLE2 AS TABLE (
ID INT NOT NULL,
CAT_NAM_1 VARCHAR(10) NULL,
CAT_NAM_2 VARCHAR(10) NULL,
CAT_NAM_3 VARCHAR(10) NULL,
CAT_NAM_4 VARCHAR(10) NULL
);
INSERT INTO #TABLE2(ID,CAT_NAM_1,CAT_NAM_2,CAT_NAM_3,CAT_NAM_4)
VALUES (1,'A',NULL,NULL,NULL),(2,NULL,'B',NULL,NULL);
;WITH CAT_NAM AS (
SELECT ID, [NAME]
FROM #TABLE1
WHERE YEAR([DATE]) = YEAR(GETDATE())
AND ID IN (20,23,25,30,37,40)
)
SELECT CASE
WHEN EXISTS(SELECT 1 FROM CAT_NAM WHERE CAT_NAM.[NAME] = CAT_NAM_1) THEN CAT_NAM_1
WHEN EXISTS(SELECT 1 FROM CAT_NAM WHERE CAT_NAM.[NAME] = CAT_NAM_2) THEN CAT_NAM_2
WHEN EXISTS(SELECT 1 FROM CAT_NAM WHERE CAT_NAM.[NAME] = CAT_NAM_3) THEN CAT_NAM_3
WHEN EXISTS(SELECT 1 FROM CAT_NAM WHERE CAT_NAM.[NAME] = CAT_NAM_4) THEN CAT_NAM_4
ELSE '?' -- not sure what you want if there is no match
END AS CAT
FROM #TABLE2;
You can do a bit of set-based logic for this
SELECT
ct.NAME
FROM table2 t2
CROSS APPLY (
SELECT v.NAME
FROM (VALUES
(t2.CAT_NAM_1),
(t2.CAT_NAM_2),
(t2.CAT_NAM_3),
(t2.CAT_NAM_4)
) v(NAME)
INTERSECT
SELECT ct.NAM
FROM CAT_NAM ct
WHERE ct.ID IN (20,23,25,30,37)
) ct;

Group/Summarize each row with removal row if total quantity is 0

How to group/summarize as example image below.
The same data will be grouped based on Date and Item columns.
The quantity will be sum.
If the negative quantity is more than total quantity of the min date (total qty = 0), that row will be removed.
This condition will continue for the next min date as well.
In this case 1-Jan-2020 and 2-Jan-2020 will be removed because it negative quantity is more than total of those 2 days.
In case you want sample table, please use script below.
CREATE TABLE #temp_table(
[id] [int] IDENTITY(1,1) NOT NULL,
[trans_date] [date] NOT NULL,
[item] [nvarchar](40) NOT NULL,
[qty] [int] NOT NULL,
)
INSERT INTO #temp_table ( trans_date, item, qty )
VALUES
( '1-Jan-2020', 'Item A', 2 )
INSERT INTO #temp_table ( trans_date, item, qty )
VALUES
( '2-Jan-2020', 'Item A', 4 )
INSERT INTO #temp_table ( trans_date, item, qty )
VALUES
( '3-Jan-2020', 'Item B', 1 )
INSERT INTO #temp_table ( trans_date, item, qty )
VALUES
( '3-Jan-2020', 'Item A', 3 )
INSERT INTO #temp_table ( trans_date, item, qty )
VALUES
( '4-Jan-2020', 'Item A', -1 )
INSERT INTO #temp_table ( trans_date, item, qty )
VALUES
( '5-Jan-2020', 'Item A', -6 )
INSERT INTO #temp_table ( trans_date, item, qty )
VALUES
( '6-Jan-2020', 'Item A', 4 )
SELECT * FROM #temp_table
DROP TABLE #temp_table
My 1st attempt was
select
trans_date
, item
, SUM(qty)
from temp_table
group BY
trans_date
, item
My 2nd attempt, this attempt is feel like I'm lacking of some condition to reduce the next row when I first row is 0.
select
temp_table.trans_date
, temp_table.item
, SUM(temp_table.qty) + SUM(neg_table.neg_qty)
from temp_table
OUTER APPLY (
SELECT ISNULL( SUM(neg.qty), 0) AS neg_qty FROM pca_temp_table neg
WHERE 1=1
and temp_table.item = neg.item
and neg.qty < 0
) as neg_table
WHERE qty > 0
group BY
trans_date
, item
Hope this query works fine for you:
select MAX(CASE WHEN Quantity>0 THEN DATE ELSE NULL END), ITEM, SUM(Quantity)
from #T
group BY ITEM

SQL Transpose Data with Column Name

I am trying to transpose data in a SQL Server table with one row of data but with several columns, all into one column along with their respective column headers.
Original Data Table:
**TABLE Column Names:** Id, ColumnA , ColumnB , ColumnC , StartDate
**Data:** 1, 'aa' , 'bb' , 'cc', 2016-10-10
Required Format of Data:
**ColumnName Values**
Id 1
ColumnA aa
ColumnB bb
ColumnC cc
StartDate 2016-10-10
CREATE DATABASE ToDelete
GO
USE [ToDelete]
GO
CREATE TABLE [dbo].[sourceData](
[id] [int] NULL,
[ColumnA] [varchar](50) NULL,
[ColumnB] [varchar](50) NULL,
[ColumnC] [varchar](50) NULL,
[StartDate] [datetime] NULL
)
GO
INSERT [dbo].[sourceData] ([id], [ColumnA], [ColumnB], [ColumnC], [StartDate], [EndDate]) VALUES (1, 'aa', N'bb', N'cc', GETDATE())
GO
The query I am using to pull the table column names is:
SELECT c.name
FROM sys.tables t
JOIN sys.columns c
ON t.object_id = c.object_id
WHERE t.name = 'sourceData'
Your help would be appreciated.
Thank you
Here is an option that may help you create something more like an EAV structure
Example
Declare #YourTable Table ([Id] varchar(50),[ColumnA] varchar(50),[ColumnB] varchar(50),[ColumnC] varchar(50),[StartDate] date)
Insert Into #YourTable Values
(1,'aa','bb','cc','2016-10-10')
Select A.ID
,C.*
From #YourTable A
Cross Apply ( values (cast((Select A.* for XML RAW) as xml))) B(XMLData)
Cross Apply (
Select Field = a.value('local-name(.)','varchar(100)')
,Value = a.value('.','varchar(max)')
From B.XMLData.nodes('/row') as C1(n)
Cross Apply C1.n.nodes('./#*') as C2(a)
Where a.value('local-name(.)','varchar(100)') not in ('ID','OtherColumnsTo','Exclude')
) C
Returns
ID Field Value
1 ColumnA aa
1 ColumnB bb
1 ColumnC cc
1 StartDate 2016-10-10
Try the Following Solution, I have Referred from the following article to write this query:
https://www.red-gate.com/simple-talk/sql/t-sql-programming/questions-about-pivoting-data-in-sql-server-you-were-too-shy-to-ask/
USE [ToDelete]
GO
DECLARE #sql AS NVARCHAR(2000);DECLARE #col AS NVARCHAR(2000);
DECLARE #col1 AS NVARCHAR(2000);
SELECT #col = ISNULL(#col + ', ', '') +
concat('cast(',QUOTENAME(column_name),'as nvarchar(max))',' ',
QUOTENAME(column_name) ),#col1=ISNULL(#col1 + ', ', '') +QUOTENAME(column_name)
FROM (SELECT DISTINCT column_name FROM INFORMATION_SCHEMA.COLUMNS where TABLE_NAME='sourceData') AS Colname;
SET #sql =N'select columnname,[values] from (select '+#col+ ' from dbo.sourceData) as D Unpivot
([values] for columnname in (' + #col1 + '))
as unpiv'
EXEC sp_executesql #sql;
Simply use Union all like this:
select Id,'ColumnA' columnName, ColumnA [Values]
from t
union all
select Id,'ColumnB' , ColumnB
from t
union all
select Id,'ColumnC' , ColumnC
from t
union all
select Id,'StartDate' , cast(StartDate as nvarchar(max))
from t;
SQL Fiddle Demo
Additional variant using unpivot:
dataset
DECLARE #YourTable TABLE
([Id] VARCHAR(10),
[ColumnA] VARCHAR(10),
[ColumnB] VARCHAR(10),
[ColumnC] VARCHAR(10),
[StartDate] DATE
);
INSERT INTO #YourTable
VALUES
(1, 'aa', 'bb', 'cc', '2016-10-10'),
(2, 'cc', 'dd', 'zz', '2016-10-11');
query
SELECT Id,
Field,
[Value]
FROM
( SELECT Id,
ColumnA,
ColumnB,
ColumnC,
CONVERT(VARCHAR(10), StartDate) AS StartDate
FROM #YourTable
) AS t UNPIVOT([Value] FOR [Field] IN ( ColumnA,
ColumnB,
ColumnC,
StartDate)) up;

Counting and grouping challenge in a pivot table with T-SQL

I have a pivot table that converts a vertical database design to a horizontal one:
The source table:
Id ParentId Property Value
---------------------------------
1 1 Date 01-09-2015
2 1 CountValue 2
3 1 TypeA Value1
4 1 TypeB Value2
5 1 TypeC Value2
6 2 Date 15-10-2015
7 2 CountValue 3
8 2 TypeA Value3
9 2 TypeB Value22
10 2 TypeC Value99
After pivoting this looks like:
ParentId Date CountValue TypeA TypeB TypeC
----------------------------------------------------------
1 01-09-2015 2 Value1 Value2 Value2
2 15-10-2015 3 Value3 Value22 Value99
Then, there's a look-up table for valid values in columns TypeA, TypeB and TypeC:
Id Name Value
-----------------
1 TypeA Value1
2 TypeA Value2
3 TypeA Value3
4 TypeB Value20
5 TypeB Value21
6 TypeB Value22
7 TypeC Value1
8 TypeC Value2
So, given the above structure I'm looking for a way to query the pivot table in a way that I'll get a count of all invalid values in TypeA, TypeB and TypeC where Date is a valid date and CountValue is not empty and greater than 0.
How can I achieve a result that is expected and outputted like below:
Count Column
--------------
0 TypeA
1 TypeB
1 TypeC
I've accomplished the result by creating three several queries and glue the results using UNION, but I think it should also be possible using the pivot table, but I'm unsure how. Can the desired result be realized using the pivot table?
Note: the database used is a SQL Server 2005 database.
I would not approach this a PIVOT, otherwise you have to pivot your data, then unpivot it to get the output required. Breaking it down step by step you can get your valid parent IDs using this:
SELECT t.ParentID
FROM #T AS t
GROUP BY t.ParentID
HAVING ISDATE(MAX(CASE WHEN t.Property = 'Date' THEN t.Value END)) = 1
AND MAX(CASE WHEN t.Property = 'CountValue' THEN CONVERT(INT, t.Value) END) > 0;
The two having clauses limit this to your criteria of having a valid date, and a CountValue that is greater than 0
The next step would be to find your invalid properties:
SELECT t.*
FROM #T AS t
WHERE NOT EXISTS
( SELECT 1
FROM #V AS v
WHERE v.Name = t.Property
AND v.Value = t.Value
);
This will include Date, and CountValue, and also won't include TypeA because all the properties are valid, so a bit more work is required, we must find the distinct properties we are interested in:
SELECT DISTINCT Name
FROM #V
Now we can combine this with the invalid properties to get the count, and with the valid parent IDs to get the desired result:
WITH ValidParents AS
( SELECT t.ParentID
FROM #T AS t
GROUP BY t.ParentID
HAVING ISDATE(MAX(CASE WHEN t.Property = 'Date' THEN t.Value END)) = 1
AND MAX(CASE WHEN t.Property = 'CountValue' THEN CONVERT(INT, t.Value) END) > 0
), InvalidProperties AS
( SELECT t.Property
FROM #T AS t
WHERE t.ParentID IN (SELECT vp.ParentID FROM ValidParents AS vp)
AND NOT EXISTS
( SELECT 1
FROM #V AS v
WHERE v.Name = t.Property
AND v.Value = t.Value
)
)
SELECT [Count] = COUNT(t.Property),
[Column] = v.Name
FROM (SELECT DISTINCT Name FROM #V) AS V
LEFT JOIN InvalidProperties AS t
ON t.Property = v.Name
GROUP BY v.Name;
Which gives:
Count Column
--------------
0 TypeA
1 TypeB
1 TypeC
SCHEMA FOR ABOVE QUERIES
For SQL Server 2008+. Apologies, I don't have SQL Server 2005 anymore, and forgot it doesn't support table value constructors.
CREATE TABLE #T (Id INT, ParentId INT, Property VARCHAR(10), Value VARCHAR(10));
INSERT #T (Id, ParentId, Property, Value)
VALUES
(1, 1, 'Date', '01-09-2015'), (2, 1, 'CountValue', '2'), (3, 1, 'TypeA', 'Value1'),
(4, 1, 'TypeB', 'Value2'), (5, 1, 'TypeC', 'Value2'), (6, 2, 'Date', '15-10-2015'),
(7, 2, 'CountValue', '3'), (8, 2, 'TypeA', 'Value3'), (9, 2, 'TypeB', 'Value22'),
(10, 2, 'TypeC', 'Value99');
CREATE TABLE #V (ID INT, Name VARCHAR(5), Value VARCHAR(7));
INSERT #V (Id, Name, Value)
VALUES
(1, 'TypeA', 'Value1'), (2, 'TypeA', 'Value2'), (3, 'TypeA', 'Value3'),
(4, 'TypeB', 'Value20'), (5, 'TypeB', 'Value21'), (6, 'TypeB', 'Value22'),
(7, 'TypeC', 'Value1'), (8, 'TypeC', 'Value2');
Final result without PIVOT:
SELECT [count] = SUM(CASE WHEN l.id IS NULL THEN 1 ELSE 0 END)
,t.Property
FROM #lookup l
RIGHT JOIN #tab t
ON t.Property = l.Name
AND t.Value = l.Value
WHERE t.Property LIKE 'Type%'
GROUP BY t.Property;
LiveDemo
Data:
CREATE TABLE #tab(
Id INTEGER NOT NULL PRIMARY KEY
,ParentId INTEGER NOT NULL
,Property VARCHAR(10) NOT NULL
,Value VARCHAR(10) NOT NULL
);
INSERT INTO #tab(Id,ParentId,Property,Value) VALUES (1,1,'Date','01-09-2015');
INSERT INTO #tab(Id,ParentId,Property,Value) VALUES (2,1,'CountValue','2');
INSERT INTO #tab(Id,ParentId,Property,Value) VALUES (3,1,'TypeA','Value1');
INSERT INTO #tab(Id,ParentId,Property,Value) VALUES (4,1,'TypeB','Value2');
INSERT INTO #tab(Id,ParentId,Property,Value) VALUES (5,1,'TypeC','Value2');
INSERT INTO #tab(Id,ParentId,Property,Value) VALUES (6,2,'Date','15-10-2015');
INSERT INTO #tab(Id,ParentId,Property,Value) VALUES (7,2,'CountValue','3');
INSERT INTO #tab(Id,ParentId,Property,Value) VALUES (8,2,'TypeA','Value3');
INSERT INTO #tab(Id,ParentId,Property,Value) VALUES (9,2,'TypeB','Value22');
INSERT INTO #tab(Id,ParentId,Property,Value) VALUES (10,2,'TypeC','Value99');
CREATE TABLE #lookup(
Id INTEGER NOT NULL PRIMARY KEY
,Name VARCHAR(5) NOT NULL
,Value VARCHAR(7) NOT NULL
);
INSERT INTO #lookup(Id,Name,Value) VALUES (1,'TypeA','Value1');
INSERT INTO #lookup(Id,Name,Value) VALUES (2,'TypeA','Value2');
INSERT INTO #lookup(Id,Name,Value) VALUES (3,'TypeA','Value3');
INSERT INTO #lookup(Id,Name,Value) VALUES (4,'TypeB','Value20');
INSERT INTO #lookup(Id,Name,Value) VALUES (5,'TypeB','Value21');
INSERT INTO #lookup(Id,Name,Value) VALUES (6,'TypeB','Value22');
INSERT INTO #lookup(Id,Name,Value) VALUES (7,'TypeC','Value1');
INSERT INTO #lookup(Id,Name,Value) VALUES (8,'TypeC','Value2');
EDIT:
Adding more criteria:
LiveDemo2
SELECT [count] = SUM(CASE WHEN l.id IS NULL THEN 1 ELSE 0 END)
,t.Property
FROM #lookup l
RIGHT JOIN #tab t
ON t.Property = l.Name
AND t.Value = l.Value
WHERE t.Property LIKE 'Type%'
AND t.ParentId IN (SELECT ParentId FROM #tab WHERE Property = 'Date' AND ISDATE(VALUE) = 1)
AND t.ParentID IN (SELECT ParentId FROM #tab WHERE Property = 'CountValue' AND Value > 0)
GROUP BY t.Property;