Retrieve the First True Condition in a SQL Query - sql

I'm running into a problem wherein I need to get the changes of an Employee based on specific conditions.
I should retrieve rows only based on the changes below:
Assignment Category (only based on specific Categories shown in the table xxtest)
Pay Basis (only from Hourly to Salaried and Vice Versa, also shown in the table xxtest)
Both Pay Basis and Assignment Category (based on the same constraints above)
I have created a Table (XXTEST) to restrict the SQL to only reference this mapping (See DML and DDL at the end of the Question).
Basically, the Data I'm Expecting would be:
| --------|-------------------|------------------|---------------|------------- |-------------|
| Sample | FROM_PAY_BASIS_ID | TO_PAY_BASIS_ID | FROM_CATEGORY | TO_CATEGORY | CHANGE_TYPE |
| --------| ------------------| -----------------| --------------|------------- |-------------|
| 1 | 1 | 2 | FR | FR | PAY_BASIS |
| 2 | 1 | 1 | FT | FR | ASSIGN_CAT |
| 3 | 1 | 2 | FT | FR | BOTH |
the table above is based on the conditions below:
1. if BOTH, it should get "Assignment Category and Pay Basis" as its Change_Type
2. if Assignment Category, it should get "Assignment Category" as its Change_Type
3. if Pay Basis, it should get "Pay Basis" as its Change_Type
I want it to evaluate first the condition 1, and if its false, then evaluate the next until the last.
the problem occurs when both of these columns change, resulting into having 3+ rows with CHANGE_TYPE having "PAY_BASIS", "ASSIGN_CAT", "BOTH" as values.
I've tried a lot of methods but nothing seemed to fully address my need, such as the query below:
select *
from (select coalesce((select CHANGE_TYPE
from XXTEST
where FROM_CATEGORY = pax.EMPLOYMENT_CATEGORY
AND TO_CATEGORY = pax2.EMPLOYMENT_CATEGORY
AND FROM_ID = pax.PAY_BASIS_ID
and TO_ID = pax2.PAY_BASIS_ID),
select CHANGE_TYPE
from XXTEST
WHERE FROM_CATEGORY = pax.EMPLOYMENT_CATEGORY
AND TO_CATEGORY = pax2.EMPLOYMENT_CATEGORY
AND FROM_ID = 0
and TO_ID = 0),
select CHANGE_TYPE
from XXTEST
WHERE FROM_CATEGORY = 'N/A'
AND TO_CATEGORY = 'N/A'
AND FROM_ID = pax.PAY_BASIS_ID
and TO_ID = pax2.PAY_BASIS_ID),
NULL ) CHANGE_TYPE FROM DUAL ) CHANGE_TYPE
, PPX.FULL_NAME
, PPX.EMPLOYEE_NUMBER
from per_people_X ppx
, per_assignments_X pax
, per_assignments_X pax2
WHERE pax.assignment_id = pax2.assignment_id
AND PPX.PERSON_id = pax2.PERSON_id
AND PPX.PERSON_id = PAX.PERSON_id)
where CHANGE_TYPE is not null;
This kinda works but it retrieves all records, regardless if it has a match or not (due to the NULL "else" condition) and results into Change_Type = NULL.
Is it possible to just filter only those records that do not have Change_Type = NULL without encasing it in another SELECT statement?
I've also tried using CASE,
It works fine if the Employee's Pay Basis ID only changed (ex. from 1 to 2)
and if only the Employee's Category has changed (ex. from FT to FR),
but it evaluates all the cases (returning 3 rows) whenever "both" changes occur.
Any advise?

I didn't follow all the details of your post and the answers and ensuing comments, but it seems you may be after something like this. To get exactly one answer in all situations, you probably need a CASE expression. In the code below I use nested CASE expressions, but that is only to save typing (and a little bit of execution time); you could rewrite this using a single CASE expression.
The reason this works is that evaluation ends immediately as soon as the first TRUE condition in the when... then... pairs is found. You will have to figure out how to attach this to your existing query - I just put its outputs in a CTE for testing purposes below.
with
query_output ( empl_id, from_pay_basis_id, to_pay_basis_id, from_category, to_category ) as (
select 101, 1, 2, 'FR', 'FR' from dual union all
select 102, 1, 1, 'FT', 'FR' from dual union all
select 103, 1, 2, 'FT', 'FR' from dual union all
select 104, 1, 1, 'FR', 'FR' from dual
)
select empl_id, from_pay_basis_id, to_pay_basis_id, from_category, to_category,
case when from_category != to_category then
case when from_pay_basis_id != to_pay_basis_id then 'Assignment Category and Pay Basis'
else 'Assignment Category'
end
when from_pay_basis_id != to_pay_basis_id then 'Pay Basis'
end as change_type
from query_output;
EMPL_ID FROM_PAY_BASIS_ID TO_PAY_BASIS_ID FROM_CATEGORY TO_CATEGORY CHANGE_TYPE
------- ----------------- --------------- ------------- ----------- ---------------------------------
101 1 2 FR FR Pay Basis
102 1 1 FT FR Assignment Category
103 1 2 FT FR Assignment Category and Pay Basis
104 1 1 FR FR

You are probably after case statements in the where clause, something like:
SELECT PPX.FULL_NAME
, PPX.EMPLOYEE_NUMBER
, XT.CHANGE_TYPE
FROM per_people_X ppx
, XXTEST XT
, per_assignments_X pax
, per_assignments_X pax2
WHERE pax.assignment_id = pax2.assignment_id
AND PPX.PERSON_id = pax2.PERSON_id
AND PPX.PERSON_id = PAX.PERSON_id
AND (-- Both Employment Category and Pay Basis records records that were Changed
case when XT.FROM_CATEGORY = pax.EMPLOYMENT_CATEGORY
AND XT.TO_CATEGORY = pax2.EMPLOYMENT_CATEGORY
AND XT.FROM_ID = pax.PAY_BASIS_ID
AND XT.TO_ID = pax2.PAY_BASIS_ID
then 1
else 0
end = 1
OR
-- all Pay Basis records that were "Updated"
case when XT.FROM_CATEGORY = 'N/A'
AND XT.TO_CATEGORY = 'N/A'
AND XT.FROM_ID = pax.PAY_BASIS_ID
AND XT.TO_ID = pax2.PAY_BASIS_ID
then 1
else 0
end = 1
OR
-- all Assignment Category records that were "Updated"
case when XT.FROM_CATEGORY = pax.EMPLOYMENT_CATEGORY
AND XT.TO_CATEGORY = pax2.EMPLOYMENT_CATEGORY
AND XT.FROM_ID = 0
AND XT.TO_ID = 0
then 1
else 0
end = 1);
N.B. untested, since you didn't provide sample data for the per_people_x or per_assignments tables.
You may have to add extra conditions into the "both categories" case expression to exclude the other two cases; it's not immediately apparent from the data that you have supplied so far.

First of all if you use OR you should use brackets and (... or ... ) or you lose some predicates. Your first query should be rewritten to:
SELECT PPX.FULL_NAME
, PPX.EMPLOYEE_NUMBER
, XT.CHANGE_TYPE
FROM per_people_X ppx
, XXTEST XT
, per_assignments_X pax
, per_assignments_X pax2
WHERE pax.assignment_id = pax2.assignment_id
AND PPX.PERSON_id = pax2.PERSON_id
AND PPX.PERSON_id = PAX.PERSON_id
-- THIS IS THE SECTION OF THE QUERY WHERE I'M HAVING PROBLEMS --
-- Both Employment Category and Pay Basis records records that were Changed
AND (
(XT.FROM_CATEGORY = pax.EMPLOYMENT_CATEGORY
AND XT.TO_CATEGORY = pax2.EMPLOYMENT_CATEGORY
AND XT.FROM_ID = pax.PAY_BASIS_ID
AND XT.TO_ID = pax2.PAY_BASIS_ID)
-- all Pay Basis records that were "Updated"
or (XT.FROM_CATEGORY = 'N/A'
AND XT.TO_CATEGORY = 'N/A'
AND XT.FROM_ID = pax.PAY_BASIS_ID
AND XT.TO_ID = pax2.PAY_BASIS_ID)
-- all Assignment Category records that were "Updated"
or (XT.FROM_CATEGORY = pax.EMPLOYMENT_CATEGORY
AND XT.TO_CATEGORY = pax2.EMPLOYMENT_CATEGORY
AND XT.FROM_ID = 0
AND XT.TO_ID = 0)
);
EDIT: Add solution with ranking of condition
SELECT FULL_NAME
, EMPLOYEE_NUMBER
, CHANGE_TYPE
FROM (
SELECT PPX.FULL_NAME
, PPX.EMPLOYEE_NUMBER
, XT.CHANGE_TYPE
, DENSE_RANK() OVER (PRTITION BY PPX.PERSON_id,pax.assignment_id ORDER BY
CASE WHEN XT.FROM_CATEGORY = pax.EMPLOYMENT_CATEGORY
AND XT.TO_CATEGORY = pax2.EMPLOYMENT_CATEGORY
AND XT.FROM_ID = pax.PAY_BASIS_ID
AND XT.TO_ID = pax2.PAY_BASIS_ID
THEN 1
WHEN XT.FROM_CATEGORY = 'N/A'
AND XT.TO_CATEGORY = 'N/A'
AND XT.FROM_ID = pax.PAY_BASIS_ID
AND XT.TO_ID = pax2.PAY_BASIS_ID
THEN 2
ELSE 3
END
) as RNK
FROM per_people_X ppx
, XXTEST XT
, per_assignments_X pax
, per_assignments_X pax2
WHERE pax.assignment_id = pax2.assignment_id
AND PPX.PERSON_id = pax2.PERSON_id
AND PPX.PERSON_id = PAX.PERSON_id
-- THIS IS THE SECTION OF THE QUERY WHERE I'M HAVING PROBLEMS --
-- Both Employment Category and Pay Basis records records that were Changed
AND (
(XT.FROM_CATEGORY = pax.EMPLOYMENT_CATEGORY
AND XT.TO_CATEGORY = pax2.EMPLOYMENT_CATEGORY
AND XT.FROM_ID = pax.PAY_BASIS_ID
AND XT.TO_ID = pax2.PAY_BASIS_ID)
-- all Pay Basis records that were "Updated"
or (XT.FROM_CATEGORY = 'N/A'
AND XT.TO_CATEGORY = 'N/A'
AND XT.FROM_ID = pax.PAY_BASIS_ID
AND XT.TO_ID = pax2.PAY_BASIS_ID)
-- all Assignment Category records that were "Updated"
or (XT.FROM_CATEGORY = pax.EMPLOYMENT_CATEGORY
AND XT.TO_CATEGORY = pax2.EMPLOYMENT_CATEGORY
AND XT.FROM_ID = 0
AND XT.TO_ID = 0)
)
) WHERE RNK = 1;

Related

Sql Query Modification

I have a table called Customer with following schema.
Create Table Customer(id Number,customer_type varchar(20),customer_status char(1),account_number varchar(20));
Insert into Customer(id,customer_type,customer_status,account_number)values(123,'RETAIL','A','32456798');
Insert into Customer(id,customer_type,customer_status,account_number)values(123,'RETAIL','I','92456798');
Insert into Customer(id,customer_type,customer_status,account_number)values(123,'RETAIL','P','22456798');
Insert into Customer(id,customer_type,customer_status,account_number)values(123,'PERSONAL','A','42456798');
Insert into Customer(id,customer_type,customer_status,account_number)values(123,'PERSONAL','I','52456798');
Insert into Customer(id,customer_type,customer_status,account_number)values(123,'PERSONAL','P','62456798');
Insert into Customer(id,customer_type,customer_status,account_number)values(243,'PERSONAL','A','02456798');
commit;
I am trying get Id where customer status is active.Customer_type can be of two types RETAIL or PERSONAL.I just want return Retail true if id have any active reatils accounts else false,
same with Personal
I tried below query but i have trouble returning id
select REATIL,PERSONAL from (select case when customer_status = 'A' then 'Y' else 'N' end as REATIL from Customer where customer_status='A' and customer_type='RETAIL')
,(select id, case when customer_status = 'A' then 'Y' else 'N' end as PERSONAL from Customer where customer_status='A' and customer_type='PERSONAL');
Expected Output:
|---------------------|------------------|----------------|
| id | Retail | Personal |
|---------------------|------------------|----------------|
| 123 | Y | Y |
|---------------------|------------------|----------------|
| 243 | N | Y |
|---------------------|------------------|----------------|
Ay help would be appreciated.
Try the following (make modifications as per your further requirements). I did this as per given data but I feel that the data is not broad enough to test the code. And I made some assumptions as putting blank when there is no match.
Basically to determine whether Retail is Y or N, I used a case statement and did the same for Personal
-- This solution didn't fit as the OP needs 1 record per ID
select ID,
Case When customer_type = 'RETAIL' and customer_status = 'A' then 'Y'
When customer_type = 'RETAIL' and customer_status != 'A' then 'N'
Else ''
End as Retail,
Case When customer_type = 'PERSONAL' and customer_status = 'A' then 'Y'
When customer_type = 'PERSONAL' and customer_status != 'A' then 'N'
Else ''
End as PERSONAL,
account_number
from Customer
Here is the required solution
Select ID, Max(RETAIL) as RETAIL, Max(PERSONAL) as PERSONAL
from
(
select ID,
Case When customer_type = 'RETAIL' and customer_status = 'A' then 'Y'
When customer_type = 'RETAIL' and customer_status != 'A' then 'N'
Else ''
End as Retail,
Case When customer_type = 'PERSONAL' and customer_status = 'A' then 'Y'
When customer_type = 'PERSONAL' and customer_status != 'A' then 'N'
Else ''
End as PERSONAL
from Customer
) Q
Group by ID
try using a join.
the following query returns the account number instead of 'Y'
select C.id, max(R.account_number), max(P.account_number) from Customer C
left join Customer R on R.id = c.id
left join Customer P on P.id = c.id
where R.customer_type = 'RETAIL'
and R.customer_status = 'A'
and P.customer_type = 'PERSONAL'
and P.customer_status = 'A'
group by C.id

Divide column into 2

I have a table where I'm storing Allowances and Deductions. If the BaseCode is 1 then it is an allowance and if BaseCode is 2 then it is deduction.
I am trying to get the column transformed into 2 columns.
Allowance Deduction
Something Something
SELECT (
SELECT INN.FullName AS Benefit
FROM [AppCNF].[tbl_AllowanceOrBenefitType] INN
WHERE INN.BASECODE = 1
AND INN.ID = OUTR.ID
)
, FullName AS Deductions
FROM [AppCNF].[tbl_AllowanceOrBenefitType] OUTR
WHERE BASECODE = 2
This is what I have tried so far but it is giving NULL for Allowances.
Not sure what exactly you are after, but most likely you can use CASE:
SELECT
ID
,CASE WHEN BASECODE = 1 THEN FullName END AS Benefit
,CASE WHEN BASECODE = 2 THEN FullName END AS Deductions
-- ,... other columns ...
FROM [AppCNF].[tbl_AllowanceOrBenefitType]
;
You can use CASE to condition a result from a column.
SELECT
IsAllowance = CASE WHEN OUTR.BASECODE = 1 THEN 'Yes' END,
IsDeduction = CASE WHEN OUTR.BASECODE = 2 THEN 'Yes' END,
OUTR.*
FROM
[AppCNF].[tbl_AllowanceOrBenefitType] OUTR

How to filter rows based on group values in SQL?

I have a table with the following format
serialnumber,test,result
-------------------------
ABC 1 "TOO HIGH"
ABC 2 "PASS"
ABC 3 "TOO LOW"
DEF 1 "PASS"
DEF 2 "PASS"
DEF 3 "PASS"
I need to do two operations:
1) for each serial number that has all pass records, I need to roll it up into a single record
2) for every serial that contains a "TOO HIGH" or "TOO LOW" record, I need to exclude all "PASS" records for that serial number
How would I go about doing this in teradata 15, preferably in a single statement?
SELECT *
FROM tab
QUALIFY
-- #1, only PASS
( SUM(CASE WHEN result <> 'PASS' THEN 1 ELSE 0 end)
OVER (PARTITION BY serialnumber) = 0
AND ROW_NUMBER()
OVER (PARTITION BY serialnumber
ORDER BY test) = 1
)
OR
-- #2
( SUM(CASE WHEN result <> 'PASS' THEN 1 ELSE 0 end)
OVER (PARTITION BY serialnumber) > 0
AND result_ <> 'PASS'
)
Consider a union query combining both conditions, using an aggregate query for #1 and a inner join query with derived tables for #2. Hopefully, Teradata's dialect supports the syntax:
SELECT TableName.SerialNumber,
Min(TableName.Test) As Test,
Min(TableName.Result) As Result
FROM SerialNumber
GROUP BY SerialNumber
HAVING Sum(CASE WHEN TableName.Result='"PASS"' THEN 1 ELSE 0 END) = Count(*)
UNION
SELECT TableName.SerialNumber,
TableName.Test,
TableName.Result
FROM SerialNumber
INNER JOIN
(SELECT SerialNumber FROM SerialNumber
WHERE TableName.Result = '"TOO HIGH"') AS toohighSub
INNER JOIN
(SELECT SerialNumber FROM SerialNumber
WHERE TableName.Result = '"TOO LOW"') AS toolowSub
ON toolowSub.SerialNumber = toohighSub.SerialNumber
ON TableName.SerialNumber = toolowSub.SerialNumber
WHERE TableName.Result <> '"PASS"';

Not getting desire SQL output with inner query

Table-1: NominationPeriods
----------------------
Id Period Status
----------------------
1 9 Unlocked
3 8 locked
----------------------
Table-2 : NominationRevisions
-------------------------------------------
Id Revision Period Status
-------------------------------------------
15 1 9 M
19 2 9 R
20 3 9 A
--------------------------------------------
Query:
SELECT Period
,nomper.STATUS
,(
CASE
WHEN (
(
SELECT (
CASE
WHEN STATUS IN ('P','A')
THEN 'TRUE'
ELSE 'FALSE'
END
)
FROM NominationRevisions
WHERE revision = (
SELECT max(revision)
FROM NominationRevisions
WHERE Period = nomper.Period
)
AND NomPeriodNbr = nomper.Period
) = 'TRUE'
)
THEN 'TRUE'
ELSE 'FALSE'
END
) AS Flag
FROM NominationPeriods nomper
Expected Output:
-------------------------------------
Period Status Flag
-------------------------------------
9 Unlocked TRUE
8 locked TRUE
-------------------------------------
Actual Output:
-------------------------------------
Period Status Flag
-------------------------------------
9 Unlocked TRUE
-------------------------------------
I want all NominationPeriods list as output having
Highest Revision of the Period is 'A' or 'P' then Flag=TRUE
If no Revision found for a period then also return Flag=TRUE
Try this:
select "Period", "Status",
Coalesce((select top 1 case when r."Status" in ('A', 'P') then 'TRUE' else 'FALSE' end from NominationRevisions r where p.Period = r.Period order by r.Revision desc), 'TRUE') "Flag"
from NominationPeriods p
Now I believe it's OK.
I expect this might work for you, using JOIN:
SELECT
np.*,
COALESCE(
IF( nr.`Status` IS NULL, 'TRUE', NULL),
IF(nr.`Status` IN ('A', 'R'), 'TRUE', NULL),
'FALSE'
) AS 'Flag'
FROM nominationperiods np
LEFT JOIN nominationrevisions nr ON
np.Period = nr.Period
AND nr.Revision = (SELECT MAX(nr.Revision)
FROM nominationrevisions nr
WHERE nr.Period = np.Period)
The join takes max revision only, and then uses coalesce() to test all conditions for true, with a fallback to false.
I rewrited your query with less cases and in a didatic manner. See this fiddle for a working example usind the data your provided.
The point is: Return all Nomination Period but only set flag to TRUE if the last revision got an A or P status.
select nomper.Period, nomper.Status
,case when
(
exists
(
select 1
from dbo.[NominationRevisions] nr
join
(
select max(nr0.Revision) as MaxRevision, nr0.Period
from dbo.[NominationRevisions] nr0
group by nr0.Period
) as nr1 on nr1.Period = nr.Period
and nr1.MaxRevision = nr.Revision
where nr.Status = 'A' or nr.Status = 'P'
)
)
then 'TRUE'
else 'FALSE'
end
from dbo.[NominationPeriods] nomper

Getting a summary report based on grouping 2 user IDs

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 :-