Divide column into 2 - sql

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

Related

SQL query to fetch the result set with same status

The table 1 is as follows,
ID
FK1_ID
FK2_ID
1
1
1
2
1
2
3
1
3
The table with FK2 is as follows,
ID
Type
Status
1
Type1
True
2
Type2
True
3
Type1
False
The FK2_ID column is the ID column of table 2.
The expected result is, for any FK1_ID(which I have as a list of IDs), need to check all its FK2 entries in the 2nd table of Type1 and status True.
For example:
Here, I want to return YES, if all the Type1 entries are True for the specific FK1_ID. Else NO.
So, for FK1_ID with 1, the FK2 table has 3 records. Of which Type1 has 2 records. I should return YES, if both Type1 records are True, else NO.
I want accomplish this using SQL.
Any help is appreciated?
Looks like you just need to compare a conditional count of Status to the full count, with a CASE for the final result.
SELECT
t1.FK1_ID,
Result = CASE WHEN COUNT(*) = COUNT(CASE WHEN FK2.Status = 'True' THEN 1 END)
THEN 'Yes'
ELSE 'No' END
FROM table1 t1
JOIN FK2 ON FK2.ID = t1.FK2_ID
AND FK2.Type = 'Type1'
GROUP BY
t1.FK1_ID;
A slightly shorter but less understandable version
CASE WHEN COUNT(*) = COUNT(NULLIF(FK2.Status, 'False'))
Alternatively
CASE WHEN COUNT(NULLIF(FK2.Status, 'True')) = 0
I'm not totally following your logic (how these two tables are joined) but sounds like you want to compare a total count with a conditional count so maybe something like
with t as (select type, count(status) as cnt,
sum(case when status ='True' then 1 else 0 end) as truecnt
from FK2
group by type)
select type, case when truecnt > 0 and cnt = truecnt then 'Yes' else 'No' end as MyResult
from t

Require help on Inner join query on single table

I have single table called TEST as follow :
job_id input_id match_outcome
101 1 MATCH
101 2 NO_MATCH
201 1 NO_MATCH
201 2 MATCH
Expected outcome:
job_id input_id match_outcome
201 1 NO_MATCH
101 2 NO_MATCH
Query I used:
select *
from ( select * from TEST where job_id = '101') q1 join
(select * from TEST where job_id = '201') q2
where q1.match_outcome= 'MATCH' and q2.match_outcome= 'NO_MATCH' OR
q2.match_outcome= 'MATCH' and q1.match_outcome= 'NO_MATCH'
Overall objective:
I need input_id and other data which is MATCH with one job_id and and the input id which is NO MATCH in another set of job id.But this query takes longer times since these table contains millions of record and I didn't see the outcome yet.(Fyi, I am using hive tables) any efficient or any different better way to don this!! Thanks
If I try to understand this: "I need input_id . . . which is MATCH with one job_id and and the input id which is NO MATCH in another set of job id", then you can use aggregation:
select input_id
from text
group by input_id
having sum(case when match_outcome = 'MATCH' then 1 else 0 end) > 0 and
sum(case when match_outcome = 'NO MATCH' then 1 else 0 end) > 0;
This assumes that input_id is not duplicated for a give job_id, which seems consistent with the data in the question.
If you want the original data row, then you can join this into the query:
select t.*
from test t join
(select input_id
from text
group by input_id
having sum(case when match_outcome = 'MATCH' then 1 else 0 end) > 0 and
sum(case when match_outcome = 'NO MATCH' then 1 else 0 end) > 0
) i
on t.input_id = i.input_id;
Select * from TEST
Where match_outcome='NO_MATCH'

Case SQL If there is no record between dates

I'm new to SQL and am struggling with a case.
I would like to make the case where if an account (account_ID) doesn't have a record (ON billing_id) between current_date-302 and current_date-62 THEN MARK WITH A "1"
Query below:
Thanks in advance
SELECT
billing_date_local_time
,account_id
,contract_owner_name
,date_first_feature_partner
,deal_starts_at
,contract_id
,new_partner_type
,sum(voucher_sold) AS Vouchers
,sum(gross_bookings_local) AS GB
,sum(gross_revenue_local) AS GR
,is_G2
,Case when billing_date_local_time between current_date-302 and current_date-62 = 0 THEN 'YES' ELSE 'NO' End
FROM EMEA_ANALYTICS.eu_deal_flat
WHERE
country_id = 206
and billing_date_local_time between current_date-400
and current_date-2
GROUP BY 1,2,3,4,5,6,10,11
You'll need to do a correlated subquery; something like this:
select
a.billing_date_local_time
,a.account_id
,...
, CASE WHEN EXISTS (SELECT * FROM EMEA_ANALYTICS.eu_deal_flat b WHERE a.account_id = b.account_id AND b.billing_date_local_time between current_date-302 and current_date-62 ) THEN 'YES' ELSE 'NO' END
from
FROM EMEA_ANALYTICS.eu_deal_flat a
WHERE ...
You need to apply an aggregate function like this:
min(case when billing_date_local_time
between current_date-302 and current_date-62
then 0
else 1
end)

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)

SQL using CASE in SELECT with GROUP BY. Need CASE-value but get row-value

so basicially there is 1 question and 1 problem:
1. question - when I have like 100 columns in a table(and no key or uindex is set) and I want to join or subselect that table with itself, do I really have to write out every column name?
2. problem - the example below shows the 1. question and my actual SQL-statement problem
Example:
A.FIELD1,
(SELECT CASE WHEN B.FIELD2 = 1 THEN B.FIELD3 ELSE null FROM TABLE B WHERE A.* = B.*) AS CASEFIELD1
(SELECT CASE WHEN B.FIELD2 = 2 THEN B.FIELD4 ELSE null FROM TABLE B WHERE A.* = B.*) AS CASEFIELD2
FROM TABLE A
GROUP BY A.FIELD1
The story is: if I don't put the CASE into its own select statement then I have to put the actual rowname into the GROUP BY and the GROUP BY doesn't group the NULL-value from the CASE but the actual value from the row. And because of that I would have to either join or subselect with all columns, since there is no key and no uindex, or somehow find another solution.
DBServer is DB2.
So now to describing it just with words and no SQL:
I have "order items" which can be divided into "ZD" and "EK" (1 = ZD, 2 = EK) and can be grouped by "distributor". Even though "order items" can have one of two different "departements"(ZD, EK), the fields/rows for "ZD" and "EK" are always both filled. I need the grouping to consider the "departement" and only if the designated "departement" (ZD or EK) is changing, then I want a new group to be created.
SELECT
(CASE WHEN TABLE.DEPARTEMENT = 1 THEN TABLE.ZD ELSE null END) AS ZD,
(CASE WHEN TABLE.DEPARTEMENT = 2 THEN TABLE.EK ELSE null END) AS EK,
TABLE.DISTRIBUTOR,
sum(TABLE.SOMETHING) AS SOMETHING,
FROM TABLE
GROUP BY
ZD
EK
TABLE.DISTRIBUTOR
TABLE.DEPARTEMENT
This here worked in the SELECT and ZD, EK in the GROUP BY. Only problem was, even if EK was not the designated DEPARTEMENT, it still opened a new group if it changed, because he was using the real EK value and not the NULL from the CASE, as I was already explaining up top.
And here ladies and gentleman is the solution to the problem:
SELECT
(CASE WHEN TABLE.DEPARTEMENT = 1 THEN TABLE.ZD ELSE null END) AS ZD,
(CASE WHEN TABLE.DEPARTEMENT = 2 THEN TABLE.EK ELSE null END) AS EK,
TABLE.DISTRIBUTOR,
sum(TABLE.SOMETHING) AS SOMETHING,
FROM TABLE
GROUP BY
(CASE WHEN TABLE.DEPARTEMENT = 1 THEN TABLE.ZD ELSE null END),
(CASE WHEN TABLE.DEPARTEMENT = 2 THEN TABLE.EK ELSE null END),
TABLE.DISTRIBUTOR,
TABLE.DEPARTEMENT
#t-clausen.dk: Thank you!
#others: ...
Actually there is a wildcard equality test.
I am not sure why you would group by field1, that would seem impossible in your example. I tried to fit it into your question:
SELECT FIELD1,
CASE WHEN FIELD2 = 1 THEN FIELD3 END AS CASEFIELD1,
CASE WHEN FIELD2 = 2 THEN FIELD4 END AS CASEFIELD2
FROM
(
SELECT * FROM A
INTERSECT
SELECT * FROM B
) C
UNION -- results in a distinct
SELECT
A.FIELD1,
null,
null
FROM
(
SELECT * FROM A
EXCEPT
SELECT * FROM B
) C
This will fail for datatypes that are not comparable
No, there's no wildcard equality test. You'd have to list every field you want tested individually. If you don't want to test each individual field, you could use a hack such as concatenating all the fields, e.g.
WHERE (a.foo + a.bar + a.baz) = (b.foo + b.bar + b.az)
but either way, you're listing all of the fields.
I might tend to solve it something like this
WITH q as
(SELECT
Department
, (CASE WHEN DEPARTEMENT = 1 THEN ZD
WHEN DEPARTEMENT = 2 THEN EK
ELSE null
END) AS GRP
, DISTRIBUTOR
, SOMETHING
FROM mytable
)
SELECT
Department
, Grp
, Distributor
, sum(SOMETHING) AS SumTHING
FROM q
GROUP BY
DEPARTEMENT
, GRP
, DISTRIBUTOR
If you need to find all rows in TableA that match in TableB, how about INTERSECT or INTERSECT DISTINCT?
select * from A
INTERSECT DISTINCT
select * from B
However, if you only want rows from A where the entire row matches the values in a row from B, then why does your sample code take some values from A and others from B? If the row matches on all columns, then that would seem pointless. (Perhaps your question could be explained a bit more fully?)