Getting a summary report based on grouping 2 user IDs - sql

I have a table as such:
MsgID MsgrUserID MsgdUserID MsgDate Message
1 1 4 6/12/2015 Jules - Did you pick up the blueprints?
2 4 1 6/15/2015 Yes, they're in my hands
3 4 1 6/15/2015 Let me know when you can talk
4 3 4 6/16/2015 Jules, let's meet tomorrow
5 1 4 6/17/2015 I'm available at 2 PM today
6 1 3 7/4/2015 Cindy, did you check your mail?
7 4 3 7/3/2015 OK, I'm free after 3PM
8 3 1 7/2/2015 Yes, there was nothing there
9 2 1 7/5/2015 Plan is going well. Just need more time
10 1 2 7/5/2015 OK, great. Let me know
What I need to do is get a report that sums up all of the correspondence. It would look something like this:
User: 1
Correspondence between you and 2: 2 Last correspondence: 7/5/2015
Correspondence between you and 3: 2 Last correspondence: 7/4/2015
Correspondence between you and 4: 4 Last correspondence: 6/17/2015
Or something like that. So, I need to figure out how to sum the number of correspondence, but also get other pieces of information from the original table. The problem I'm having is that I can't figure out how to link the sum to the original table, because it's conditional. Sometimes the user's ID is in the Msgr (Messenger) field, and sometimes it's in the Msgd (Messaged) field.
I've got this monster, but I know the join to #MyMsgs table is where the error lies.
with cte as (
select
MessagedUserID as MessagedUserIDOrig,
MessagerUserID as MessagerUserIDOrig,
case when MessagerUserID < MessagedUserID
then MessagerUserID else MessagedUserID end MessagerUserID,
case when MessagerUserID > MessagedUserID
then MessagerUserID else MessagedUserID end MessagedUserID
from tmpMessaged
)
select MessagerUserID, MessagedUserID, count(*) as Contact
into #MyMsgs
from cte
WHERE MessagerUserID = #MyID
OR MessagedUserID = #MyID
group by MessagerUserID, MessagedUserID
SELECT
T1.*,
Mgr.UserName as MessagerName,
Mgr.UserID as UserID,
CASE WHEN T1.MessagedUserID = #MyID THEN Mgd.UserImg1 ELSE Mgr.UserImg1 END as UserImg1,
Mgd.UserName as MessagedName,
CC.Contact,
Mgd.LastLoginDate as LastOnline,
CASE WHEN T1.MessagedUserID = #MyID THEN 'Received' ELSE 'Sent' END as LContact,
LEFT(T1.[Message], 100) + '...' as [uMessage],
CASE WHEN T1.MessageViewed IS NULL THEN 'No' ELSE 'Yes' END as MsgViewed,
CASE WHEN T1.MessageFlag IS NULL THEN 'No' ELSE 'Yes' END as MsgFlagged
FROM [dbo].[tmpMessaged] T1
LEFT JOIN [dbo].[tmpUsers] Mgr
ON T1.[MessagerUserID] = Mgr.[UserID]
LEFT JOIN [dbo].[tmpUsers] Mgd
ON T1.[MessagedUserID] = Mgd.[UserID]
LEFT JOIN [dbo].[tmpMessaged] T2
ON T1.MessageID = T2.MessageID
LEFT JOIN #MyMsgs CC
ON CASE
-- WHEN T1.MessagerUserID = #MyID AND CC.MessagerUserID = T1.MessagerUserID THEN 1
WHEN T1.MessagedUserID = #MyID AND CC.MessagedUserID = T1.MessagedUserID THEN 1
ELSE 0
END = 1
WHERE
-- First grab the records where the User's ID is in the Messaged field
Mgd.[UserID] = #MyID
UNION
SELECT
T1.*,
Mgr.UserName as MessagerName,
Mgr.UserID as UserID,
CASE WHEN T1.MessagerUserID = #MyID THEN Mgr.UserImg1 ELSE Mgd.UserImg1 END as UserImg1,
Mgd.UserName as MessagedName,
CC.Contact,
Mgd.LastLoginDate as LastOnline,
CASE WHEN T1.MessagerUserID = #MyID THEN 'Sent' ELSE 'Received' END as LContact,
LEFT(T1.[Message], 100) + '...' as [uMessage],
CASE WHEN T1.MessageViewed IS NULL THEN 'No' ELSE 'Yes' END as MsgViewed,
CASE WHEN T1.MessageFlag IS NULL THEN 'No' ELSE 'Yes' END as MsgFlagged
FROM [dbo].[tmpMessaged] T1
LEFT JOIN [dbo].[tmpUsers] Mgr
ON T1.[MessagerUserID] = Mgr.[UserID]
LEFT JOIN [dbo].[tmpUsers] Mgd
ON T1.[MessagedUserID] = Mgd.[UserID]
LEFT JOIN [dbo].[tmpMessaged] T2
ON T1.MessageID = T2.MessageID
LEFT JOIN #MyMsgs CC
ON CASE
WHEN T1.MessagerUserID = #MyID AND CC.MessagerUserID = T1.MessagerUserID THEN 1
-- WHEN T1.MessagedUserID = #MyID AND CC.MessagerUserID = T1.MessagedUserID THEN 1
ELSE 0
END = 1
WHERE
-- Now grab the records where the User's ID is in the Messager field
Mgr.[UserID] = #MyID
ORDER BY T1.MessageDate DESC

You could just do the aggregation directly in the common table expression:
declare #myID int = 1;
with cte as (
select
case when MessagerUserID < MessagedUserID
then MessagerUserID else MessagedUserID end MessagerUserID,
case when MessagerUserID > MessagedUserID
then MessagerUserID else MessagedUserID end MessagedUserID,
count(*) MessageCount,
max(MessageDate) LastMessageDate
from tmpMessaged
group by
case when MessagerUserID < MessagedUserID
then MessagerUserID else MessagedUserID end,
case when MessagerUserID > MessagedUserID
then MessagerUserID else MessagedUserID end
)
select * from cte where MessagerUserID = #myID;
With your sample data this would result in:
MessagerUserID MessagedUserID MessageCount LastMessageDate
-------------- -------------- ------------ ---------------
1 2 2 2015-07-05
1 3 2 2015-07-04
1 4 4 2015-06-17
The specific formatting with headers/details etc is probably better to do in the actual reporting application, although it's certainly possibly to do directly on the server too (but who uses SSMS for pretty reports anyway).

I asked about the sender ever being the receiver and got the answer I hoped for (no). With that rule in place, you can "cheat" and double-stack the records, swapping participant 1 and participant 2 in half of them, then only concern yourself with selecting from that structure and treating participant 1 as "your guy" and participant 2 as "other guy". You'll never double-count a record when sender cannot ever equal receiver.
DECLARE #UserYouCareAbout int
SET #UserYouCareAbout = 1
SELECT CONVERT(nvarchar(max), GETDATE(), 101)
SELECT
'Correspondence between you and ' + CONVERT(nvarchar(max), [Message Participant 2]) + ': ' + STR(MAX(MsgDate), 4, 0) AS [Conversation With],
'Last correspondence: ' + CONVERT(nvarchar(max), MAX(MsgDate), 101) AS [Last Communication]
/*
--individual unformatted pieces
,
COUNT(MsgID) AS [MessageCount],
[Message Participant 2] AS [Other Guy],
MAX(MsgDate) AS [LastDate]
*/
FROM
(
(
SELECT
MsgID,
MsgrUserID AS [Message Participant 1],
MsgdUserID AS [Message Participant 2],
MsgDate
FROM
tmpMessaged
) --SentStuff
UNION ALL
(
SELECT
MsgID,
MsgdUserID AS [Message Participant 1], --note that
MsgrUserID AS [Message Participant 2], --these switched
MsgDate
FROM
tmpMessaged
) --RecStuff
) DerivedAllMessagesTwice
WHERE
[Message Participant 1] = #UserYouCareAbout
GROUP BY
[Message Participant 2]
This simplification eliminates all of the inline conditionals.

Try the following code :-
declare #MyID int = 1
create table #yourmsgtable (MsgID int, MsgrUserID int, MsgdUserID int, MsgDate date, Message varchar(max))
insert into #yourmsgtable values
(1,1,4,'6/12/2015','Jules - Did you pick up the blueprints?'),
(2,4,1,'6/15/2015','Yes, they''re in my hands'),
(3,4,1,'6/15/2015','Let me know when you can talk'),
(4,3,4,'6/16/2015','Jules, let''s meet tomorrow'),
(5,1,4,'6/17/2015','I''m available at 2 PM today'),
(6,1,3,'7/4/2015','Cindy, did you check your mail?'),
(7,4,3,'7/3/2015','OK, I''m free after 3PM'),
(8,3,1,'7/2/2015','Yes, there was nothing there'),
(9,2,1,'7/5/2015','Plan is going well. Just need more time'),
(10,1,2,'7/5/2015','OK, great. Let me know')
create table #tmpmsgtable(party1 int, party2 int, msgdate date)
insert into #tmpmsgtable
select MsgrUserID, MsgdUserID, MsgDate from #yourmsgtable where MsgrUserID = #MyID
union all
select MsgdUserID, MsgrUserID, MsgDate from #yourmsgtable where MsgdUserID = #MyID
select
'User : ' + convert(varchar(max),party1) 'Party 1',
'Correspondence between you and ' + convert(varchar(max),party2) + ' : ' + convert(varchar(max),count(*)) 'Party 2 Correspondence',
'Last correspondence : ' + convert(nvarchar(max),max(msgdate)) 'Last correspondence'
from #tmpmsgtable
group by party1, party2
drop table #tmpmsgtable
drop table #yourmsgtable
Result :-

Related

Oracle Stored Procedure not loading data as expected

In testing, I did the following (which worked):
create table testdata as select * from sometable;
create procedure testload as begin
delete from testdata;
insert into testdata select * from sometable;
end;
I've used the same structure for a more complex query. If I run "insert into testdata select [new query]", it will load the data into the table. However, when I created a new stored procedure using the new query, it will execute, but won't actually load data.
Note that this query was handed off to me, I didn't write it myself. The results have been validated, so while I appreciate any and all advice on how to clean up the code, I'm primarily interested in getting the stored procedure up and running with the code as close to what is below as possible.
select
CLAIM_ID
,INTERNAL_ID
,line
,VENDOR_GROUP
,case when (CLAIM_FORMAT_RULE+ POS_RULE + POS_TYPE_RULE+ POS_CODE_RULE+ MODIFIERS_RULE+ BILL_TYPE_RULE+ ATTENDING_PROV_RULE+ REFERRING_PROV_RULE) = 8 then 'Y' else 'N' end AUTH_FLAG
from
(
SELECT
AP.CLAIM_ID
,CLM1.INTERNAL_ID
, px.line
, DAT.VENDOR_GROUP
,MAX(CASE WHEN DAT.FORMAT_C IS NULL THEN 1 WHEN REPLACE(REPLACE(AP.CLAIM_FORMAT_C,1,'CMS'),2,'UB') = UPPER(DAT.FORMAT_C) THEN 1 else 0 END) AS CLAIM_FORMAT_RULE
,MAX(CASE WHEN DAT.POS_ID IS NULL THEN 1 WHEN EAF.INTERNAL_ID = DAT.POS_ID THEN 1 else 0 end ) AS POS_RULE
,MAX(CASE WHEN DAT.POS_TYPE_C IS NULL THEN 1 WHEN NVL(PX.POS_TYPE_C,0) NOT IN (20,23) THEN 1 WHEN CAST(PX.POS_TYPE_C AS VARCHAR(10)) = DAT.POS_TYPE_C THEN 1 else 0 END) AS POS_TYPE_RULE
,MAX(CASE WHEN DAT.PROC_CODE IS NULL THEN 1 WHEN DAT.PROC_CODE LIKE '%-%' AND EAP.PROC_CODE BETWEEN STRTOK(DAT.PROC_CODE,'-',1) AND STRTOK(DAT.PROC_CODE,'-',2) THEN 1 WHEN EAP.PROC_CODE = DAT.PROC_CODE THEN 1 else 0 END) AS POS_CODE_RULE
,MAX(CASE WHEN DAT.MODIFIER IS NULL THEN 1 WHEN DAT.MODIFIER = PX.MODIFIERS THEN 1 else 0 END) AS MODIFIERS_RULE
,MAX(CASE WHEN DAT.BILL_TYPE IS NULL THEN 1 WHEN DAT.BILL_TYPE LIKE '%-%' AND AP.TYPE_OF_BILL BETWEEN STRTOK(DAT.BILL_TYPE,'-',1) AND STRTOK(DAT.BILL_TYPE,'-',2) THEN 1 WHEN AP.TYPE_OF_BILL = DAT.BILL_TYPE THEN 1 else 0 END) AS BILL_TYPE_RULE
,MAX(CASE WHEN DAT.ATTENDING_PROV_NETWORK IS NULL THEN 1 WHEN DAT.ATTENDING_PROV_NETWORK = ALV.NET_AFFIL_LEVEL_C THEN 1 else 0 END) AS ATTENDING_PROV_RULE
,MAX(CASE WHEN DAT.REFERRING_PROV_NETWORK IS NULL THEN 1 WHEN DAT.REFERRING_PROV_NETWORK = RLV.NET_AFFIL_LEVEL_C THEN 1 else 0 END) AS REFERRING_PROV_RULE
FROM HCCLSC.AP_CLAIM AP
INNER JOIN HCCLSC.CLM_MAP CLM1 ON AP.CLAIM_ID=CLM1.CID --AND CLM1.INTERNAL_ID in ('363137412', '363149130')
INNER JOIN HCCLSC.CLARITY_VENDOR VEN ON AP.VENDOR_ID = VEN.VENDOR_ID
INNER JOIN HCCLSC.VENDOR_TAX_ID VTIN ON AP.VENDOR_ID = VTIN.VENDOR_ID
INNER JOIN KPBISC_GRP_NCAR.AUTH_EXCEPTIONS DAT ON VTIN.TAX_ID = DAT.VENDOR_TIN
LEFT JOIN HCCLSC.AP_CLAIM_PX PX ON AP.CLAIM_ID = PX.CLAIM_ID
LEFT JOIN HCCLSC.CLARITY_EAP EAP ON EAP.PROC_ID = PX.PROC_ID
LEFT JOIN HCCLSC.EAF_MAP EAF ON AP.LOC_ID = EAF.CID
LEFT JOIN HCCLSC.CLARITY_SER_NETAFF ALV ON AP.ATTEND_PROV_ID = ALV.PROV_ID AND ALV.LINE = 1
LEFT JOIN HCCLSC.CLARITY_SER_NETAFF RLV ON AP.REF_PROV_ID = RLV.PROV_ID AND ALV.LINE = 1
where
TRUNC(AP.DATE_RECEIVED) BETWEEN sysdate-60 AND sysdate and
COALESCE(AP.WORKFLOW_C,0)=0
and AP.STATUS_C in (2, 4, 3)
GROUP BY AP.CLAIM_ID,CLM1.INTERNAL_ID, px.line, DAT.VENDOR_GROUP
order by AP.CLAIM_ID , px.line
)
If it's not the commit problem mentioned in the other answer, try running the elect statement on it's own, but wrapping the whole statement in a select count(*) from (your_statement);
This will tell you if your query is returning zero rows.

Returning only id's of records that meet criteria

I need to return distinct ID's of records which meet following conditions :
must have records with field reason_of_creation = 1
and must NOT have records with field reason_of_creation = 0 or null
in the same time.
While i was able to do it, i keep wondering is there more elegant (even recommended) way of doing it.
Here is anonymized version of what i have :
select distinct st.some_id from (
select st.some_id, wanted.wanted_count as wanted, unwanted.unwanted_count as unwanted
from some_table st
left join (
select st.some_id, count(st.reason_of_creation) as wanted_count
from some_table st
where st.reason_of_creation=1
group by st.some_id
) wanted on wanted.some_id = st.some_id
left join (
select st.some_id, count(st.reason_of_creation) as unwanted_count
from some_table st
where st.reason_of_creation=0
group by st.some_id
) unwanted on unwanted.some_id = st.some_id
where wanted.wanted_count >0 and (unwanted.unwanted_count = 0 or unwanted.unwanted_count is null)
) st;
Sample data :
some_id reason_of_creation
1 1
1 0
2 1
3 null
4 0
4 1
5 1
desired result would be list of records with some_id = 2, 5
It seems to me your query is overkill,all you need is some post aggregation filtering
SELECT some_id FROM t
GROUP BY some_id
HAVING SUM(CASE WHEN reason_of_creation = 1 THEN 1 ELSE 0 END)>0
AND SUM(CASE WHEN reason_of_creation = 0 OR reason_of_creation IS NULL THEN 1 ELSE 0 END)=0
I think that more elegant query exists and it is based on assumption what reasoson_of_crdeation field is integer, so minimal possible it's value, which greater than 0 is 1
This is for possible negative values for reasoson_of_crdeation:
select someid from st
where reasoson_of_crdeation != -1
group by someid
having(min(nvl(abs(reasoson_of_crdeation), 0)) = 1)
or
select someid from st
group by someid
having(min(nvl(abs(case when reasoson_of_crdeation = -1 then -2 else reasoson_of_crdeation end), 0)) = 1)
And this one in a case if reasoson_of_crdeation is non-negative integer:
select someid from st
group by someid
having(min(nvl(reasoson_of_crdeation, 0)) = 1)

case statement if table present

I am having problem in finding table from different database (table sometimes get dropped due to procedure) if the table is present then condition else direct ans as 1
select (case when exists (select * from SysSet.INFORMATION_SCHEMA .TABLES where TABLE_NAME = 'CHQPASS') then (
case when left(tranm.docu_no,1) <>'3' or tranm.docu_dt <'01/01/2015' then 1
when (select top 1 ACHD_KEY from TRAND k where k.TRN_NO = TRANM.TRN_NO and k.DR_CR ='D' ) = 'A000100010002' THEN 1
WHEN (select COUNT(*) from SYSSET..chqpass D where D.COMP_DIR ='PSAGR' and D.DOCU_DT = TRANM.DOCU_DT and D.AMT = TRAND.TOT_AMT ) <> 0
THEN 1
else cast(isnull (trand.RECONCILE,0)as int)
end)
else 1
end )as pend
if table is not present it show the error
Msg 208, Level 16, State 1, Line 2 Invalid object name
'SYSSET..chqpass'.
table not present how can i stop it to see that table
Replace following line
WHEN (select COUNT(*) from SYSSET..chqpass D where D.COMP_DIR ='xyz' and D.DOCU_DT >'01/01/2015' and D.AMT = 2556 ) <> 0
with this line
WHEN EXEC('(select COUNT(*) from SYSSET..chqpass D where D.COMP_DIR =''xyz'' and D.DOCU_DT >''01/01/2015'' and D.AMT = 2556 )') <> 0
It should work this way...
Try this try replacing the sys.tables with INformationschema so you can specify which schema the table is present in.
SELECT
(
CASE WHEN EXISTS(SELECT * FROM SYSSET.INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'CHQPASS' AND TABLE_SCHEMA = 'dbo')
THEN (
CASE WHEN LEFT(tranm.docu_no,1) <>'3' or tranm.docu_dt < '01/01/2015' THEN 1
WHEN (SELECT TOP 1 ACHD_KEY FROM TRAND k WHERE k.TRN_NO = TRANM.TRN_NO and k.DR_CR ='D' ) = 'A000100010002' THEN 1
WHEN (select COUNT(*) from SYSSET..chqpass D WHERE D.COMP_DIR ='PSAGR' and D.DOCU_DT = TRANM.DOCU_DT and D.AMT = TRAND.TOT_AMT ) <> 0 THEN 1
ELSE cast(isnull (trand.RECONCILE,0)as int)
END
)
ELSE 1
END
) as pend

Counting if data exists in a row

Hey guys I have the below sample data which i want to query for.
MemberID AGEQ1 AGEQ2 AGEQ2
-----------------------------------------------------------------
1217 2 null null
58458 3 2 null
58459 null null null
58457 null 5 null
299576 6 5 7
What i need to do is to lookup the table and if any AGEx COLUMN contains any data then it counts the number of times there is data for that row in each column
Results example:
for memberID 1217 the count would be 1
for memberID 58458 the count would be 2
for memberID 58459 the count would be 0 or null
for memberID 58457 the count would be 1
for memberID 299576 the count would be 3
This is how it should look like in SQL if i query the entire table
1 Children - 2
2 Children - 1
3 Children - 1
0 Children - 1
So far i have been doing it using the following query which isnt very efficient and does give incorrect tallies as there are multiple combinations that people can answer the AGE question. Also i have to write multiple queries and change the is null to is not null depending on how many children i am looking to count a person has
select COUNT (*) as '1 Children' from Member
where AGEQ1 is not null
and AGEQ2 is null
and AGEQ3 is null
The above query only gives me an answer of 1 but i want to be able to count the other columns for data as well
Hope this is nice and clear and thank you in advance
If all of the columns are integers, you can take advantage of integer math - dividing the column by itself will yield 1, unless the value is NULL, in which case COALESCE can convert the resulting NULL to 0.
SELECT
MemberID,
COALESCE(AGEQ1 / AGEQ1, 0)
+ COALESCE(AGEQ2 / AGEQ2, 0)
+ COALESCE(AGEQ3 / AGEQ3, 0)
+ COALESCE(AGEQ4 / AGEQ4, 0)
+ COALESCE(AGEQ5 / AGEQ5, 0)
+ COALESCE(AGEQ6 / AGEQ6, 0)
FROM dbo.table_name;
To get the number of people with each count of children, then:
;WITH y(y) AS
(
SELECT TOP (7) rn = ROW_NUMBER() OVER
(ORDER BY [object_id]) - 1 FROM sys.objects
),
x AS
(
SELECT
MemberID,
x = COALESCE(AGEQ1 / AGEQ1, 0)
+ COALESCE(AGEQ2 / AGEQ2, 0)
+ COALESCE(AGEQ3 / AGEQ3, 0)
+ COALESCE(AGEQ4 / AGEQ4, 0)
+ COALESCE(AGEQ5 / AGEQ5, 0)
+ COALESCE(AGEQ6 / AGEQ6, 0)
FROM dbo.table_name
)
SELECT
NumberOfChildren = y.y,
NumberOfPeopleWithThatMany = COUNT(x.x)
FROM y LEFT OUTER JOIN x ON y.y = x.x
GROUP BY y.y ORDER BY y.y;
I'd look at using UNPIVOT. That will make your wide column into rows. Since you don't care about what value was in a column, just the presence/absence of value, this will generate a row per not-null column.
The trick then becomes mashing that into the desired output format. It could probably have been done cleaner but I'm a fan of "showing my work" so that others can conform it to their needs.
SQLFiddle
-- Using the above logic
WITH HadAges AS
(
-- Find everyone and determine number of rows
SELECT
UP.MemberID
, count(1) AS rc
FROM
dbo.Member AS M
UNPIVOT
(
ColumnValue for ColumnName in (AGEQ1, AGEQ2, AGEQ3)
) AS UP
GROUP BY
UP.MemberID
)
, NoAge AS
(
-- Account for those that didn't show up
SELECT M.MemberID
FROM
dbo.Member AS M
EXCEPT
SELECT
H.MemberID
FROM
HadAges AS H
)
, NUMBERS AS
(
-- Allowable range is 1-6
SELECT TOP 6
ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS TheCount
FROM
sys.all_columns AS SC
)
, COMBINATION AS
(
-- Link those with rows to their count
SELECT
N.TheCount AS ChildCount
, H.MemberID
FROM
NUMBERS AS N
LEFT OUTER JOIN
HadAges AS H
ON H.rc = N.TheCount
UNION ALL
-- Deal with the unlinked
SELECT
0
, NA.MemberID
FROM
NoAge AS NA
)
SELECT
C.ChildCount
, COUNT(C.MemberID) AS Instances
FROM
COMBINATION AS C
GROUP BY
C.ChildCount;
Try this:
select id, a+b+c+d+e+f
from ( select id,
case when age1 is null then 0 else 1 end a,
case when age2 is null then 0 else 1 end b,
case when age3 is null then 0 else 1 end c,
case when age4 is null then 0 else 1 end d,
case when age5 is null then 0 else 1 end e,
case when age6 is null then 0 else 1 end f
from ages
) as t
See here in fiddle http://sqlfiddle.com/#!3/88020/1
To get the quantity of persons with childs
select childs, count(*) as ct
from (
select id, a+b+c+d+e+f childs
from
(
select
id,
case when age1 is null then 0 else 1 end a,
case when age2 is null then 0 else 1 end b,
case when age3 is null then 0 else 1 end c,
case when age4 is null then 0 else 1 end d,
case when age5 is null then 0 else 1 end e,
case when age6 is null then 0 else 1 end f
from ages ) as t
) ct
group by childs
order by 1
See it here at fiddle http://sqlfiddle.com/#!3/88020/24

counting records on the same table with different values possibly none sql server 2008

I have a inventory table with a condition i.e. new, used, other, and i am query a small set of this data, and there is a possibility that all the record set contains only 1 or all the conditions. I tried using a case statement, but if one of the conditions isn't found nothing for that condition returned, and I need it to return 0
This is what I've tried so far:
select(
case
when new_used = 'N' then 'new'
when new_used = 'U' then 'used'
when new_used = 'O' then 'other'
end
)as conditions,
count(*) as count
from myDB
where something = something
group by(
case
when New_Used = 'N' then 'new'
when New_Used = 'U' then 'used'
when New_Used = 'O' then 'other'
end
)
This returns the data like:
conditions | count
------------------
new 10
used 45
I am trying to get the data to return like the following:
conditions | count
------------------
new | 10
used | 45
other | 0
Thanks in advance
;WITH constants(letter,word) AS
(
SELECT l,w FROM (VALUES('N','new'),('U','used'),('O','other')) AS x(l,w)
)
SELECT
conditions = c.word,
[count] = COUNT(x.new_used)
FROM constants AS c
LEFT OUTER JOIN dbo.myDB AS x
ON c.letter = x.new_used
AND something = something
GROUP BY c.word;
try this -
DECLARE #t TABLE (new_used CHAR(1))
INSERT INTO #t (new_used)
SELECT t = 'N'
UNION ALL
SELECT 'N'
UNION ALL
SELECT 'U'
SELECT conditions, ISNULL(r.cnt, 0) AS [count]
FROM (
VALUES('U', 'used'), ('N', 'new'), ('O', 'other')
) t(c, conditions)
LEFT JOIN (
SELECT new_used, COUNT(1) AS cnt
FROM #t
--WHERE something = something
GROUP BY new_used
) r ON r.new_used = t.c
in output -
new 2
used 1
other 0
You can do it as a cross-tab:
select
sum(case when new_used = 'N' then 1 else 0 end) as N,
sum(case when new_used = 'U' then 1 else 0 end) as U,
sum(case when new_used = 'O' then 1 else 0 end) as Other
from myDB
where something = something