Wrong Output in the FULL OUTER JOIN query - sql

Table Structures:
tblCustomer
Customer_id created field1 field2 cardno field14
------------------------------------------------------------------------------------------------
1014 2010-05-25 12:51:59.547 Cell Phone abc#lmn.com 1234567890 Test Card
1015 2010-08-15 12:51:59.547 Email abc#xyz.com 2345678891
tbl_TransactionDishout
Trnx_id offerNo TerminalID Created VirtualCard
-------------------------------------------------------------------
1 1014 170924690436418 2010-05-25 12:51:59.547 1234567890
Is it possible to get the result as below date-wise records:
Enrolled Enrolled as Email Enrolled as Text Deals Redeemed
<First Date> 7 5 2 6
<Next Date> 9 3 6 14
Existing query:
SELECT
convert(varchar, CAST(ISNULL(t1.created,t2.created) AS DATETIME), 111) created,
COUNT(CASE WHEN (t1.field1 = 'E-mail' or t1.field1 = 'Cell Phone') and (t1.field14 <> 'Test Card' or t1.field14 is null) THEN 1 END) Enrolled,
t1.field14,
COUNT(CASE WHEN t1.field1 = 'E-mail' and (t1.field14 <> 'Test Card' and t1.field14 is null) THEN 1 END) Enrolled_as_Email,
COUNT(CASE WHEN t1.field1 = 'Cell Phone' and (t1.field14 <> 'Test Card' and t1.field14 is null) THEN 1 END) Enrolled_as_Cell,
COUNT(CASE WHEN t2.DishoutResponseCode = '0000' and (t1.field14 <> 'Test Card' and t1.field14 is null) THEN 1 END) Deals_Redeemed
FROM
tblCustomer AS t1
FULL OUTER JOIN
tbl_TransactionDishout t2
ON t1.cardno = t2.VirtualCard
AND t1.created = t2.created
GROUP BY
convert(varchar, CAST(ISNULL(t1.created,t2.created) AS DATETIME), 111),
t1.field14
ORDER BY
convert(varchar, CAST(ISNULL(t1.created,t2.created) AS DATETIME), 111) DESC
Now, here I am facing one problem that the fourth column is executing something wrong because I have One record in tbl_TransactionDishout table yesterday which has responsecode = 0000 and also is not a 'Test card' but still I am getting 0 count.
relation between tbl_transaction and tblCustomer is having same cardno...

Based on what you have said in the comments section, I think you need to change one snippet of code...
What I want is that card should not have field14 as 'Test card'
(t1.field14 <> 'Test Card' and t1.field14 is null)
=>
(t1.field14 <> 'Test Card' OR t1.field14 is null)
Build up a logic table to check if you really want AND or if you want OR
field14 | (field14 <> 'Test Card') | (t1.field14 is null) | A OR B | A AND B
--------------------------------------------------------------------------------
'Test Card' | FALSE | FALSE | FALSE | FALSE
NULL | NULL | TRUE | TRUE | FALSE
'Any Card' | TRUE | FALSE | TRUE | FALSE
EDIT Follow up to comment
Using OR in the code above can't yield TRUE when Field14 is 'Test Card'. Both tests yield FALSE and so the result must be FALSE.
You need to break things down in stages. Debugging should be done by testing pieces at a time and graddually proving what work to isolate what doesn't. Never try to sort everything out at once, approach things methodically.
Run this test...
SELECT
*,
CASE WHEN field14 <> 'Test Card' THEN 1 ELSE 0 END Test1,
CASE WHEN field14 IS NULL THEN 1 ELSE 0 END Test2,
CASE WHEN field14 <> 'Test Card' OR field14 IS NULL THEN 1 ELSE 0 END 1_OR_2,
CASE WHEN field14 <> 'Test Card' AND field14 IS NULL THEN 1 ELSE 0 END 1_AND_2
FROM
tblCustomer

Related

SQL query case when without else or do nothing?

Supposed I have some sample data in table_name_a as below:
code val_a val_b remark date
------------------------------------------
1 00001 500 0.1 111 20191108
2 00001 1000 0.2 222 20191109
3 00002 200 0.1 111 20191110
4 00002 400 0.3 222 20191111
5 00001 200 0.2 333 20191112
6 00001 400 0.1 444 20191113
My expected output as below:
code 111_a 111_b 222_a 222_b 333_a ....
--------------------------------------------
1 00001 500 .. .. .. ..
And below SQL query will contain 0 value which covered the correct values, does it possible to query without Else or do nothing?
SELECT code, date,
CASE WHEN t.remark='111' THEN t.val_a ELSE 0 END 111_a,
CASE WHEN t.remark='111' THEN t.val_b ELSE 0 END 111_b,
CASE WHEN t.remark='222' THEN t.val_a ELSE 0 END 222_a,
CASE WHEN t.remark='222' THEN t.val_b ELSE 0 END 222_b,
CASE WHEN t.remark='333' THEN t.val_a ELSE 0 END 333_a,
CASE WHEN t.remark='333' THEN t.val_b ELSE 0 END 333_b,
CASE WHEN t.remark='444' THEN t.val_a ELSE 0 END 444_a,
CASE WHEN t.remark='444' THEN t.val_b ELSE 0 END 444_b,
FROM table_name_a t
You need to use MAX with pivoting logic here, though you are on the right track:
SELECT
code,
MAX(CASE WHEN remark = '111' THEN val_a END) 111_a,
MAX(CASE WHEN remark = '111' THEN val_b END) 111_b,
MAX(CASE WHEN remark = '222' THEN val_a END) 222_a,
MAX(CASE WHEN remark = '222' THEN val_b END) 222_b,
MAX(CASE WHEN remark = '333' THEN val_a END) 333_a,
MAX(CASE WHEN remark = '333' THEN val_b END) 333_b,
MAX(CASE WHEN remark = '444' THEN val_a END) 444_a,
MAX(CASE WHEN remark = '444' THEN val_b END) 444_b
FROM table_name_a
GROUP BY
code;
The logic here works because for each group of records belonging to a single code, we take the maximum value only under certain conditions, in this case for certain values of remark. Should the condition be false, then the CASE expressions would return NULL, which would then be ignored by MAX.

Conditional count when case = 1, DB2

I'm currently trying to figure out the best way to do a conditional count as an alias in DB2 for Iseries. The below values represent job statuses where a job can be created, completed and cancelled so any one job will possibly have multiple status codes attached to it.
However, for my final value, I'm trying to get a count of jobs that only have the created status so that I can show how many are still open jobs. Basically looking for cases where the count for the created case = 1, but the below fails at the '='
SELECT
COUNT(CASE A1.JOB WHEN = 'CREATED' THEN 1 END) AS CREATED,
COUNT(CASE A1.JOB WHEN = 'CANCELLED' THEN 1 END) AS CANCELLED,
COUNT(CASE WHEN A1.JOB 'CREATED' = 1 then 1 END) AS OPEN
FROM SCHEMA.TABLE A1;
sample data and results:
Job ID | Status_code
-------------------------
123 'CREATED'
123 'COMPLETED'
521 'CREATED'
521 'CANCELLED'
645 'CREATED'
Results:
JOB | CREATED | CANCELLED | OPEN
-------------------------------------------
123 1 0 0
521 1 1 0
645 1 0 1
Assuming that the only "close" status is 'CANCELLED', you can use not exists like this:
select count(*)
from schema.table t
where t.status_code = 'CREATED' and
not exists (select 1
from schema.table t2
where t2.job = t.job and
t2.status_code in ('CANCELLED', 'COMPLETED', 'DELETED')
);
If you want multiple counts, then filtering like this does not work. So aggregate by job first:
select sum(is_created) as num_created,
sum(is_cancelled) as num_cancelled,
sum(is_created * (1 - is_cancelled) * (1 - is_completed) * (1 - is_deleted)) as open
from (select job,
max(case when status_code = 'CREATED' then 1 else 0 end) as is_created,
max(case when status_code = 'CANCELLED' then 1 else 0 end) as is_cancelled,
max(case when status_code = 'COMPLETED' then 1 else 0 end) as is_completed,
max(case when status_code = 'DELETED' then 1 else 0 end) as is_deleted
from t
group by job
) j
The following returns the result you need:
WITH TAB (Job_ID, JOB) AS
(
VALUES
(123, 'CREATED')
, (123, 'COMPLETED')
, (521, 'CREATED')
, (521, 'CANCELLED')
, (645, 'CREATED')
)
SELECT
Job_ID
, COUNT(CASE A1.JOB WHEN 'CREATED' THEN 1 END) AS CREATED
, COUNT(CASE A1.JOB WHEN 'CANCELLED' THEN 1 END) AS CANCELLED
, CASE
WHEN NULLIF(COUNT(1), 0) = COUNT(CASE A1.JOB WHEN 'CREATED' then 1 END)
THEN 1
ELSE 0
END AS OPEN
FROM TAB A1
GROUP BY JOB_ID;
With conditional aggregation:
SELECT
JobID,
MAX(CASE Status_code WHEN 'CREATED' THEN 1 ELSE 0 END) AS CREATED,
MAX(CASE Status_code WHEN 'CANCELLED' THEN 1 ELSE 0 END) AS CANCELLED,
MIN(CASE WHEN Status_code <> 'CREATED' THEN 0 ELSE 1 END) AS OPEN
FROM tablename
GROUP BY JobID
See the demo.
Results:
> JobID | CREATED | CANCELLED | OPEN
> ----: | ------: | --------: | ---:
> 123 | 1 | 0 | 0
> 521 | 1 | 1 | 0
> 645 | 1 | 0 | 1
Assuming valid close status is either "COMPLETED" or "CANCELLED", you can try following SQL.
SELECT
A1.JobID,
sum(CASE WHEN A1.Status_code = 'CREATED' THEN 1 ELSE 0 END) AS CREATED,
sum(CASE WHEN A1.Status_code = 'CANCELLED' THEN 1 ELSE 0 END) AS CANCELLED,
(
SUM(CASE WHEN A1.Status_code = 'CREATED' THEN 1 ELSE 0 END)
- sum(CASE WHEN A1.Status_code = 'CANCELLED' THEN 1 ELSE 0 END)
- sum(CASE WHEN A1.Status_code = 'COMPLETED' THEN 1 ELSE 0 END)
) AS OPEN
FROM SCHEMA.TABLE A1
GROUP BY A1.JobID

how to separated One column to two with cases

I have a table and I would want to separate the data to multiple columns, how i can do it ?
I tried this:
select a.[batch],a.[Doc_Type],
Soaking Out =
CASE a.[Doc_Type]
WHEN 'BB' THEN 'Soaking Out'
END,
Soaking In =
CASE a.[Doc_Type]
WHEN 'AA' THEN 'Soaking In'
END,
FROM Transaction_Hdr a JOIN Transaction_dtl b
on a.Doc_Number=b.Doc_Number
Your original query would output the strings 'soaking in' or 'soaking out', but what is needed in those case expressions (after then) is the column [Qty] and it is that value which will be returned from the case expression.
What I don't know is which table [Qty] comes from but I assume it is the detail table (b) otherwise there isn't much point in joining that detail table.
SELECT
a.[Doc_Type]
, a.[batch]
, CASE a.[Doc_Type] WHEN 'BB' THEN b.Qty END [soaking out]
, CASE a.[Doc_Type] WHEN 'AA' THEN b.Qty END [soaking in]
FROM Transaction_Hdr a
JOIN Transaction_dtl b ON a.Doc_Number = b.Doc_Number
ORDER BY
a.[Doc_Type]
, a.[batch]
But: a "detail" table and a "header" table usually indicates many rows of detail for a single header. So you might need a SUM() and GROUP BY
SELECT
h.[Doc_Type]
, h.[batch]
, SUM(CASE h.[Doc_Type] WHEN 'BB' THEN d.Qty END) [soaking out]
, SUM(CASE h.[Doc_Type] WHEN 'AA' THEN d.Qty END) [soaking in]
FROM Transaction_Hdr h
JOIN Transaction_dtl d ON h.Doc_Number = d.Doc_Number
GROUP BY
h.[Doc_Type]
, h.[batch]
ORDER BY
h.[Doc_Type]
, h.[batch]
Note I have now used aliases "h" = "header" and "d" = "detail" as I am really not keen of aliases that rely on a sequence within the query (as that sequence can get messed with very easily). I find it way easier for an alias to easily identify its associated table by "first letter of each word in a table's name" or similar.
select a.[batch],a.[Doc_Type],
isnull(CASE WHEN a.[Doc_Type]='AA' THEN convert(real,a.Qty) END,0) as [Soaking In] ,
isnull(CASE WHEN a.[Doc_Type]='BB' THEN convert(real,a.Qty) END ,0)as [Soaking Out]
FROM Transaction_Hdr a
I think you are looking for quantity in result table, So you should use that instead of string 'Soaking In' and 'Soaking Out' as follows
select a.[batch],a.[Doc_Type],
SoakingOut =
CASE a.[Doc_Type]
WHEN 'BB' THEN Qty
END ,
SoakingIn =
CASE a.[Doc_Type]
WHEN 'AA' THEN Qty
END
FROM #temp a
BEGIN TRAN
CREATE TABLE #Data (
Doc_Type VARCHAR(10),
Batch INT,
Qty DECIMAL(4,2)
);
INSERT INTO #Data VALUES
('AA', 1, 20.5),
('BB', 2, 10 ),
('AA', 3, 6 ),
('BB', 4, 7 ),
('AA', 5, 8 );
SELECT ISNULL(CASE WHEN Doc_Type='AA'THEN CONVERT(NVARCHAR(10),QTY) END,'') Soaking_In ,
ISNULL(CASE WHEN Doc_Type='BB'THEN CONVERT(NVARCHAR(10),QTY) END,'') Soaking_Out
FROM #Data
ROLLBACK TRAN
Use CASE() and Modulus as below, assuming that Batch is always inceremnted by 1 and Doc_Type has always those two values AA and BB in the same order:
CREATE TABLE Data (
Doc_Type VARCHAR(10),
Batch INT,
Qty DECIMAL(4,2)
);
INSERT INTO Data VALUES
('AA', 1, 20.5),
('BB', 2, 10 ),
('AA', 3, 6 ),
('BB', 4, 7 ),
('AA', 5, 8 );
SELECT D.Doc_Type, D.Batch,
CASE WHEN D.Batch % 2 = 0 Then 0 ELSE D.Qty END AS Soaking_In,
CASE WHEN D.Batch % 2 = 1 Then 0 ELSE D.Qty END AS Soaking_Out
FROM Data D;
Results:
+----------+-------+------------+-------------+
| Doc_Type | Batch | Soaking_In | Soaking_Out |
+----------+-------+------------+-------------+
| AA | 1 | 20,50 | 0,00 |
| BB | 2 | 0,00 | 10,00 |
| AA | 3 | 6,00 | 0,00 |
| BB | 4 | 0,00 | 7,00 |
| AA | 5 | 8,00 | 0,00 |
+----------+-------+------------+-------------+
Demo

SQL: Flag Duplicate Records Using Case Statement WHERE FIELD VALUE1 <>FIELD VALUE 2 & FIELD VALUE1 DATE > FIELD VALUE2

I'm working on a SQL query that counts duplicate records that are based on a text field I am working with: where datasource = 'Web' or 'Internal'. I am currently using a case statement to count the number of times a record shows that value. My question is how do I return values (i'm thinking a case statement with an indicator (1, or 0)) that shows where datasource = 'Web' and date > datasource = 'Internal' and date?
web.datasource date > internal.datasource date
I'm attaching a query of what I currently have working, what my output is and what I would like the end result to look like.
SELECT id
,lastname
,firstname
,datasource
,CASE
WHEN (
(Datasource = 'Web')
)THEN Count(Datasource)
ELSE 0
END WebData
,CASE
WHEN (
(Datasource = 'Internal')
) THEN Count(Datasource)
ELSE 0
END InternalData
,count(id) as countid
,date
FROM Table
GROUP BY
id
,lastname
,firstname
,datasource
,date
This currently returns:
12345 Jack Boss Internal 0 1 1 2015-03-25
12241 Eric Graves Internal 0 1 1 2015-04-01
13300 Su Lynn Web 1 0 1 2016-02-01
13300 Su Lynn Internal 0 1 1 2015-08-07
13914 Mark Ross Internal 0 2 2 2015-05-01
14008 Mitch Smith Web 1 0 1 2016-03-07
14008 Mitch Smith Internal 0 1 1 2015-06-02
This is what I would like the end Result to look like:
12345 Jack Boss Internal 0 1 1 2015-03-25 0
12241 Eric Graves Internal 0 1 1 2015-04-01 0
13300 Su Lynn Web 1 0 1 2016-02-01 0
13300 Su Lynn Internal 0 1 1 2015-08-07 0
13914 Mark Ross Internal 0 2 2 2015-05-01 0
14008 Mitch Smith Web 1 0 1 2016-03-07 1
14008 Mitch Smith Internal 0 1 1 2015-06-02 1
OR
14008 Mitch Smith 1 1 2
Ideas? Thanks.
This might get you started:
SELECT id
,lastname
,firstname
,datasource
,CASE
WHEN (
(Datasource = 'Web')
)THEN Count(Datasource)
ELSE 0
END WebData
,CASE
WHEN (
(Datasource = 'Internal')
) THEN Count(Datasource)
ELSE 0
END InternalData
,count(id) as countid
,date
, sub_table.an_indicator
FROM Table
, ( select t2.id as id
, case when h_table.web_date > h_table.internal_date
then 1
else 0 end as an_indicator
from( select t2.id as id
, max( date ) as web_date
, null as internal_date
from table t2
where t2.id=Table.id
and t2.lastname = Table.lastname
and t2.firstname = Table.firstname
and t2.datasource = 'Web'
group by t2.id
union
select t2.id
, null
, max( date )
from table t2
where t2.id=Table.id
and t2.lastname = Table.lastname
and t2.firstname = Table.firstname
and t2.datasource = 'Internal'
group by t2.id
) h_table
) sub_table
where sub_table.id = Table.id
select
id, lastname, firstname, datasource
case when Datasource = 'Web' then count(Datasource) else 0 end as WebData,
case when Datasource = 'Internal' then count(Datasource) else 0 end as InternalData,
count(id) as CountId,
"date",
min(dups.flag) as dup
from
<table> as t
inner join
(
select
id, lastname, firstname,
case
when max(case when datasource = 'web' then "date" end) >
max(case when datasource = 'internal' then "date" end)
then 1 else 0
end as flag
from <table>
group by
id, lastname, firstname
) as dups
on dups.id = t.id
and dups.lastname = t.lastname and dups.firstname = t.firstname
group by
id, lastname, firstname, datasource
Any chance this one might work?
select
id, lastname, firstname, datasource
case when Datasource = 'Web' then count(Datasource) else 0 end as WebData,
case when Datasource = 'Internal' then count(Datasource) else 0 end as InternalData,
count(id) as CountId,
"date",
case when max(case when datasource = 'web' then "date" end)
over (partition by id, lastname, firstname) >
max(case when datasource = 'internal' then "date" end)
over (partition by id, lastname, firstname)
then 1
else 0
end as dup
from
<table> as t
group by
id, lastname, firstname, datasource

Combining rows with NULL columns

select
COUNT(Table1.ID) as count_shipped,
null as count_shipped
from Table1
where
table1.saleStatus='shipped'
and table1.saleApproved='yes'
union
select
null,
COUNT(Table1.ID) as count_pending
from Table1
where
table1.saleStatus in ('Pending', 'awaiting payment', 'backorder')
This gives this output
count_shipped count_shipped
NULL 5
4 NULL
but I don't want Null I only want 4 5 in one line Can anybody help me how to do this sql server?
You can use a case to sum up your conditions
select sum(case when saleStatus = 'shipped' and table1.saleApproved = 'yes'
then 1
else 0
end) as count_shipped,
sum(case when saleStatus in ('Pending', 'awaiting payment', 'backorder')
then 1
else 0
end) as count_pending
from Table1