T-SQL - subqueries on rows grouped by ID to create a summary table - sql

I have a table "MyTable" with an id and two int fields "A" and "B":
MyTable
+-------+-----+-----+
| ID | A | B |
+-------+-----+-----+
| 99 | 0 | 1 |
| 99 | 0 | 1 |
| 99 | 0 | 0 |
| 99 | 1 | 1 |
| 99 | 0 | 1 |
| 100 | 1 | 0 |
| 100 | 0 | 0 |
| 100 | 0 | 0 |
| 444 | 1 | 0 |
| 88 | 0 | 0 |
| 88 | 0 | 0 |
| 88 | 0 | 1 |
+-------+-----+-----+
I'd like a T-SQL query to return a single row for each distinct id, which contains:
each distinct ID
whether there exists a row for that ID with a non-zero value for "a"
whether there exists a row for that ID with a non-zero value for "b"
like so:
+-------+-----+-----+
| ID | A | B |
+-------+-----+-----+
| 99 | 1 | 1 |
| 100 | 1 | 0 |
| 444 | 1 | 0 |
| 88 | 0 | 1 |
+-------+-----+-----+
I can GROUP BY the ID, but I don't know how to create the joins or subqueries on each group to get the desired result.

select id, max(case when A<>0 then 1 else 0 end)A, max(case when B<>0 then 1 else 0 end)B
from mytable
group by id
Or you can just use since your value is 1 and 0. But if value is other than that please use first query.
select id, max(A)A, max(B)B
from mytable
group by id

Related

How to assign duplicate increment in SQL?

While going through SQL columns, if we find text match "NEW" in Calc column, update the incrementing a count starting with 1 in Results column.
It should look like this on the output:
The following uses an id column to resolve the order issue. Replace that with your corresponding expression. This also addresses the requirement to start the display sequence with 1 and also show 0 for the 'NEW' rows.
The SQL (updated):
SELECT logs.*
, CASE WHEN text = 'NEW' THEN 0
ELSE
COALESCE(SUM(CASE WHEN text = 'NEW' THEN 1 END) OVER (PARTITION BY xrank ORDER BY id)+1, 1)
END AS display
FROM logs
ORDER BY id
The result:
+----+-------+------+---------+
| id | xrank | text | display |
+----+-------+------+---------+
| 1 | 1 | A | 1 |
| 2 | 1 | B | 1 |
| 3 | 1 | C | 1 |
| 4 | 1 | NEW | 0 |
| 5 | 1 | D | 2 |
| 6 | 1 | Q | 2 |
| 7 | 1 | B | 2 |
| 8 | 1 | NEW | 0 |
| 9 | 1 | D | 3 |
| 10 | 1 | Z | 3 |
| 11 | 2 | A | 1 |
| 12 | 2 | B | 1 |
| 13 | 2 | C | 1 |
| 14 | 2 | NEW | 0 |
| 15 | 2 | D | 2 |
| 16 | 2 | Q | 2 |
| 17 | 2 | B | 2 |
| 18 | 2 | NEW | 0 |
| 19 | 2 | D | 3 |
| 20 | 2 | Z | 3 |
+----+-------+------+---------+
You need a column that specifies the ordering for the table. With that, just use a cumulative sum:
select t.*,
1 + sum(case when Calc = 'NEW' then 1 else 0 end) over (partition by Rank_Id order by Seq) as display
from t;

Subtract values in each row of a column based on a WHERE and GROUP BY statement in SQL

I would like to subtract each row "Value" with the "Value" where Sub1=0 grouping by ID_1 and ID_2 using a SQL query.
This is the table structure:
------------------------------------
ID_1 |ID_2 | sub1 | Value
------------------------------------
1 | a | 0 | 20
1 | a | 50 | 30
1 | a | 100 | 40
1 | b | 0 | 25
1 | b | 50 | 30
1 | b | 100 | 50
2 | a | 0 | 5
2 | a | 50 | 10
2 | a | 100 | 30
2 | b | 0 | 25
2 | b | 50 | 50
2 | b | 100 | 70
I would like to group by ID_1 and ID_2 and subtract each row's value with the value where the Sub1=0
Output table should be :
------------------------------------
ID_1 |ID_2 | sub1 | Value | Diff
------------------------------------
1 | a | 0 | 20 | 0
1 | a | 50 | 30 | 10
1 | a | 100 | 40 | 20
1 | b | 0 | 25 | 0
1 | b | 50 | 30 | 5
1 | b | 100 | 50 | 25
2 | a | 0 | 5 | 0
2 | a | 50 | 10 | 5
2 | a | 100 | 30 | 25
2 | b | 0 | 25 | 0
2 | b | 50 | 50 | 25
2 | b | 100 | 70 | 45
Use a window function:
select t.*,
(value -
sum(case when sub1 = 0 then value else 0 end) over (partition by id_1, id_2)
) as diff
from t;
This should work:
select t1.*, t1.value - t2.value as diff
from t t1
left join t t2 on t2.id_1 = t1.id_1 and t2.id_2 = t1.id_2 and t2.sub1 = 0
See it here:
http://sqlfiddle.com/#!9/cab4d5/1

SQL - Partition restarted based on a column value

I need to create a new column that restarts at every 0 value of Column Repeated Call of each Customer_ID:
+-------------+---------+----------------------+---------------+
| Customer_ID | Call_ID | Days Since Last Call | Repeated Call |
+-------------+---------+----------------------+---------------+
| 1 | 1 | Null | 0 |
| 1 | 2 | 45 | 0 |
| 1 | 3 | 0 | 1 |
| 1 | 4 | 0 | 1 |
| 1 | 5 | 0 | 1 |
| 1 | 6 | 48 | 0 |
| 1 | 7 | 1 | 1 |
| 2 | 8 | Null | 0 |
| 2 | 9 | 1 | 1 |
+-------------+---------+----------------------+---------------+
In to something like this:
+-------------+---------+----------------------+---------------+-------------+
| Customer_ID | Call_ID | Days Since Last Call | Repeated Call | Order_Group |
+-------------+---------+----------------------+---------------+-------------+
| 1 | 1 | Null | 0 | 1 |
| 1 | 2 | 45 | 0 | 2 |
| 1 | 3 | 0 | 1 | 2 |
| 1 | 4 | 0 | 1 | 2 |
| 1 | 5 | 0 | 1 | 2 |
| 1 | 6 | 48 | 0 | 3 |
| 1 | 7 | 1 | 1 | 3 |
| 2 | 8 | Null | 0 | 1 |
| 2 | 9 | 1 | 1 | 1 |
+-------------+---------+----------------------+---------------+-------------+
Appreciate your suggestion, thanks!
You can use SUM() window function:
select t.*,
sum(case when Repeated_Call = 0 then 1 else 0 end)
over (partition by Customer_ID order by Call_Id) Order_Group
from tablename t
See the demo (for MySql but it is standard SQL).
Results:
| Customer_ID | Call_ID | Days Since Last Call | Repeated_Call | Order_Group |
| ----------- | ------- | -------------------- | ------------- | ----------- |
| 1 | 1 | | 0 | 1 |
| 1 | 2 | 45 | 0 | 2 |
| 1 | 3 | 0 | 1 | 2 |
| 1 | 4 | 0 | 1 | 2 |
| 1 | 5 | 0 | 1 | 2 |
| 1 | 6 | 48 | 0 | 3 |
| 1 | 7 | 1 | 1 | 3 |
| 2 | 8 | | 0 | 1 |
| 2 | 9 | 1 | 1 | 1 |
You can calculation every 0 value in column Repeated Call (for each customer) using window analytic function COUNT with ROWS UNBOUNDED PRECEDING:
SELECT *,
COUNT(CASE WHEN Repeated Call=0 THEN 1 ELSE NULL END )OVER(PARTITION BY Customer_ID
ORDER BY Call_ID ROWS UNBOUNDED PRECEDING)Order_Gr FROM Table

How to set value based on value existence in SQL Server?

I have the following T-SQL code:
select
id,
(case
when n in(Bla1', 'Bla2') then 1
when n = 'Bla3' then 99
else 0
end) as c
from
hello
Running this code outputs this result:
| id | c |
+--------+----+
| 577140 | 0 |
| 577140 | 1 |
| 577140 | 0 |
| 577140 | 0 |
| 577140 | 99 |
| 577141 | 0 |
| 577141 | 0 |
| 577141 | 0 |
| 577142 | 0 |
| 577142 | 0 |
| 577142 | 1 |
How can I modify the code to get the following output?
| id | c |
+--------+----+
| 577140 | 99 |
| 577141 | 0 |
| 577142 | 1 |
Rule
For each id: If 99 exists, then c becomes 99. If not, either 1 or 0, depending if any 1 exists.
You can use aggregation:
select id,
max(case when n in ('Bla1', 'Bla2') then 1
when n = 'Bla3' then 99
else 0
end) as c
from hello
group by id;

Presto SQL - Trying to pull data from multiple columns into one entry to find a unique, missing, or dupe entry

new to SQL/Presto here.
Feel free to point out the obvious if needed.
I have a sub query that pulls data into a table like below.
For each ItemID, 1 would mean that the tag is on, 0 is off.
I am trying to make a query that would pull up each ItemID with its associated tag if its unique, otherwise point out if there is more than one or if its missing.
Data_Table
| ItemID | TagA | TagB | TagC | TagD | TagE |
| 111 | 1 | 1 | 0 | 0 | 0 |
| 222 | 1 | 1 | 1 | 0 | 0 |
| 333 | 1 | 1 | 0 | 0 | 0 |
| 444 | 0 | 1 | 0 | 0 | 0 |
| 555 | 0 | 0 | 0 | 0 | 0 |
| 666 | 0 | 0 | 0 | 1 | 1 |
I tried a case when statement that pull each 1 and another case query that tries to convert each column into just one row entry.
SELECT Item_ID,
CASE WHEN (Tag_A+Tag_B+Tag_C+Tag_D+Tag_E > 1) THEN 'Dupe'
ELSE (CASE WHEN Tag_A = 1 THEN 'TagA_Present'
WHEN Tag_B = 1 THEN 'TagB_Present'
WHEN Tag_C = 1 THEN 'TagC_Present'
WHEN Tag_D = 1 THEN 'TagD_Present'
WHEN Tag_E = 1 THEN 'TagE_Present'
ELSE 'Missing_Tag' END)
END as ItemTag
FROM Data_Table
EDITED - I went too far with the sample data and initial query has been changed.
Actual Results
| ItemID | ItemTag |
| 111 | Dupe |
| 222 | TagA_Present |
| 333 | TagB_Present |
| 444 | TagB_Present |
| 555 | Missing |
| 666 | TagD_Present |
ItemID 111, 222, 333, and 666 should all be 'Dupe', but the results seems to be deeming random ones unique.
Hmmm. I am thinking:
select t.itemId,
(case when (TagA + TagB + TagC + TagD + TagE) > 1 then 'Dupe'
when TagA = 1 then 'TagA'
when TagB = 1 then 'TagB'
when TagC = 1 then 'TagC'
when TagD = 1 then 'TagD'
when TagE = 1 then 'TagE'
else 'Missing'
end) as ItemTag
from Data_Table;
There is no reason to use aggregation for this.