Retrieve data from sql column by splitting one column into two - sql

ID DepID Status
------------------
000 54 0
000 12 1
141 14 0
141 56 1
000 12 0
000 89 1
I have the above table in which I have the depID. The following is the output I need:
ID DepOld DepNew
-------------------
000 54 12
141 14 56
000 12 89
Status of 0 means its old and 1 means new. How do I get the above output, considering it's in one table?
I can't use the IN clause.
I tried the following
SELECT
ID,
Max(CASE
WHEN Status = 0 THEN DepID
END) DepOld,
Max(CASE
WHEN Status = 1 THEN DepID
END) DepNew
FROM
tablename
GROUP BY
ID
but this the output I get
Id DepOld DepNew
--------------------
000 54 54
000 12 NULL
141 14 14
141 56 Null
if i pass depID=54 then this output is what i want
ID DepOld DepNew
000 54 12

You can use conditional aggregation:
select id,
max(case when status = 0 then DepID end) as DepOld,
max(case when status = 1 then DepID end) as DepNew
from table t
group by id;

If you'll only ever have two rows per ID, one with Status = 0 and the other with Status = 1, you could join the table to itself based on the ID column so you have both the old and new Department IDs available in a single row:
SELECT old.ID, old.DepID AS DepOld, new.DepID AS DepNew
FROM your_table old
INNER JOIN your_table new ON old.ID = new.ID AND new.Status = 1
WHERE old.Status = 0

Using Case statement and Max aggragate you can get the result.
CREATE TABLE #fast
(
ID VARCHAR(100),
DepID INT,
Status INT
)
INSERT INTO #fast
VALUES ( '000',54,0),
('000',12,1),
('141',14,0),
('141',56,1),
('000',12,0),
('000',89,1)
SELECT ID,
Max(CASE
WHEN Status = 0 THEN DepID
END) DepOld,
Max(CASE
WHEN Status = 1 THEN DepID
END) DepNew
FROM tablename
GROUP BY ID

Related

How do I create a query in MS Access that finds and displays parents from the same table?

I have an MS Access table, which contains information about individuals within households. I need a way to link the adult record to the child record. These are literal parent/child records, but all held in a single table. The parent/child records share the Household_ID field. Assume at this stage that each household has 0,1 or 2 children and 1 or 2 adults. I can work on the more complex scenarios, just need to know where to start! Thanks for your help.
For example:
Person_ID Household_ID Age Gender
1 1 8 F
2 1 42 M
3 1 44 F
So for this household I'd like:
Household_ID Child_Age Child_Gender Adult_M_Age Adult_F_Age
1 8 F 42 44
You appear to want:
select t.*
from (select t.*,
max(case when gender = 'M' and age >= 18 then age end) over (partition by household_id) as adult_m_age,
max(case when gender = 'M' and age >= 18 then age end) over (partition by household_id) as adult_f_age
from t
) t
where age < 18;
EDIT:
In MS Access, you would phrase this differently. One method uses subqueries;
select t.*,
(select top 1 t2.age
from t as t2
where t2.household_id = t.household_id and
t2.gender = 'M' and
t2.age >= 18
) as adult_m_age,
(select top 1 t2.age
from t as t2
where t2.household_id = t.household_id and
t2.gender = 'F' and
t2.age >= 18
) as adult_f_age
from t
where age < 18;
Use conditional aggregation, apply your criteria to detect member's role. For example using Age-based criteria
select Household_ID,
max(case when Age < 18 then Age end) as Child_Age,
max(case when Age < 18 then Gender end) as Child_Gender,
max(case when Age >= 18 and Gender ='M' then Age end) as Adult_M_Age,
max(case when Age >= 18 and Gender ='F' then Age end) as Adult_F_Age
from tbl
group by Household_ID

how to get the count of data based on status id in sql

i have following table
id statusid
100 1
100 2
100 3
101 1
101 3
i am getting the result like following
id data1 data2 data3
100 1 1 1
101 1 0 1
but i want the result like following
id data1 data2+data3
100 1 2
101 1 1
i am using the following query:
select id, SUM(CASE WHEN statusid=1 THEN 1 ELSE 0 END) AS data1,
SUM(CASE WHEN statusid=2 THEN 1 ELSE 0 END) AS data2,
SUM(CASE WHEN statusid=3 THEN 1 ELSE 0 END) AS data3
from employee
group by id
any help.
thank you.
Sudha.
You can count statuses 2 and 3 together like so:
select id,
sum(case when statusid = 1 then 1 else 0 end) as data1,
sum(case when statusid in (2, 3) then 1 else 0 end) as data2_3
from employee
group by id
You may use PIVOT clause to get the required result.
Use DECODE to map the status so that the 2 and 3 produce the same value
with tab2 as (select
id, decode(status_id,3,2,status_id) status_id2
from tab)
select * from tab2
PIVOT (count(*) "CNT" for status_id2 in
(1 as "DATA_1",
2 as "DATA_2_3")
)
ID DATA_1_CNT DATA_2_3_CNT
---------- ---------- ------------
100 1 2
101 1 1

To 'flag' a specific condition in SQL query

I have a result set in the below format and I need to flag "GroupColumn"
-------------------------------------------------------------------
ID GroupColumn ConditionCol1 ConditionCol2
-------------------------------------------------------------------
1 101 ABC 99
2 101 DEF 99
3 102 ABC 01
4 102 DEF 01
5 103 ABC 02
6 103 DEF 99
7 104 DEF 02
8 104 DEF 99
First of the I need to flag the data based on "GroupColumn", with in this "GroupColumn" I am looking to satisfy Condition of "ABC" from one row and "99" from another row but not necessarily from the same row.
I looking to get a final result set some thing like this for the "Output" column
-------------------------------------------------------------------
ID GroupColumn ConditionCol1 ConditionCol2 Output
-------------------------------------------------------------------
1 101 ABC 99 Satisfied
2 101 DEF 99 Satisfied
3 102 ABC 01
4 102 DEF 01
5 103 ABC 02 Satisfied
6 103 DEF 99 Satisfied
7 104 DEF 02
8 104 DEF 99
You can do this using window functions:
select t.*,
(case when sum(case when conditioncol1 = 'ABC' then 1 else 0 end) over (partition by groupcolumn) > 0 and
sum(case when conditioncol2 = 99 then 1 else 0 end) over (partition by groupcolumn) > 0
then 'Satisfied'
end) as flag
from t;
An alternative is to use group by:
select t.*, tt.flag
from t join
(select groupcolumn, 'Satisfied' as flag
from t
where conditioncol1 = 'ABC' or conditioncol2 = 99
group by groupcolumn
having sum(case when conditioncol1 = 'ABC' then 1 else 0 end) > 0 and
sum(case when conditioncol2 = 99 then 1 else 0 end) > 0
) tt
on tt.groupcolumn = t.groupcolumn;
Assuming you are using SQL Server and you need to add Output column to your original table, you can try the following:
create table #temp
(GroupColumn int,ConditionCol1 varchar(20),ConditionCol2 int)
insert into #temp values (100,'ABC',99)
insert into #temp values (100,'DEF',99)
insert into #temp values (101,'ABC',02)
insert into #temp values (101,'DEF',99)
insert into #temp values (102,'DEF',99)
insert into #temp values (102,'DEF',99)
ALTER TABLE #temp
ADD [Output] varchar(10)
GO
;with cte(GroupColumn) as (
select GroupColumn
from #temp
where ConditionCol1 <> 'ABC'
and ConditionCol2 = 99
)
UPDATE t
SET [Output] = 'Satisfied'
FROM #temp t
INNER JOIN cte on t.GroupColumn = cte.GroupColumn
WHERE t.ConditionCol1 = 'ABC'
UPDATE t
SET [Output] = 'Satisfied'
FROM #temp t
WHERE [Output] is null
and t.GroupColumn in (Select GroupColumn from #temp where [Output]='Satisfied')
select * from #temp

How to write a query to filter a table according to a range of values

I have a table with columns call_no, status, and sub_staus
For ex: records are like this.
call_no status sub_staus
123 2 null
123 79 null
123 null 119
231 5 null
231 null 78
I need to fetch a call_no whose status is 79 and sub_status is 119
You can do this using aggregation and having:
select call_no
from t
group by call_no
having sum(case when status = 79 then 1 else 0 end) > 0 and
sum(case when sub_status = 119 then 1 else 0 end) > 0;
SELECT CALL_NO
FROM TABLE
GROUP BY CALL_NO
HAVING SUM(
CASE
WHEN STATUS = 79
THEN 1
ELSE 0
END) > 0
AND SUM(
CASE
WHEN SUB_STATUS = 119
THEN 1
ELSE 0
END) > 0;
I suspect you want maximum values - but this is a guess. If you want calls that have had status 79 and sub-status 119 then using SUM(case....) would apply, but using maximums may give you calls that are currently at status 79 and sub-status 119.
select call_no
from t
group by call_no
having max(status) = 79
and max(sub_status) = 119;

select from 2 tables with multiple counts

I have 2 tables I'm trying to join in a select query.
Table 1: Store, primary_key(id,store_num)
store_id store_num due_date manager_id
1 100 06-30-2024 user1
2 108 06-30-2018 user2
3 109 13-31-2014 user3
Table 2: Department, where status(A-applied,p-Pending)
store_id store_num dept_num status
1 100 201 A
1 100 202 A
1 100 203 P
1 100 204 A
1 100 205 P
1 100 206 A
Expecting to select store_id, store_num, due_date, manager_id, Applied count, pending count. The result is something looks like this.
store_id store_num due_date manager_id applied_count pending_count
1 100 06-30-2024 user1 4 2
I tried it and got where I am able to join and get it in multiple rows, But counts not working out for me. can some one help me how I can get the counts
select
store.store_id,
store.store_num,
store.due_date,
store.manager_id,
dept.status
from store as store
inner join department as dept on store.store_id = dept.store_id
and store.store_num = dept.store_num
Your query is half way done. You need to do an aggregation to get the values in different columns. This is a conditional aggregation, as shown here:
select s.store_id, s.store_num, s.due_date, s.manager_id,
sum(case when d.status = 'A' then 1 else 0 end) as Active_Count,
sum(case when d.status = 'P' then 1 else 0 end) as Pending_Count
from store s inner join
department as dept
on s.store_id = d.store_id and s.store_num = d.store_num
group by store.store_id, store.store_num, store.due_date, store.manager_id;
The expression:
sum(case when d.status = 'A' then 1 else 0 end) as Active_Count,
Is counting the rows where status = 'A'. It does so by assigning such rows a value of 1 and then summing up that value.