Select data with only specific factors from many - sql-server

I'm using T-SQL
I have a table: user session with platform source.
I need to get users who used only "Android" and "Desktop".
Data Example:
ID | Source | DateTime
1 | Android | 2016-06-01
1 | Desktop | 2016-06-01
2 | Android | 2016-06-02
3 | iOS | 2016-06-01
3 | Desktop | 2016-06-02
3 | Android | 2016-06-03
Expected result:
ID = 1
ID = 2 is wrong, because it has only "Android"
ID = 3 is wrong, because it has "IOS"

I call this a set-within-sets query. I like to approach this using group by and having, because this is a very flexible method for expressing these conditions:
select id
from t
group by id
having sum(case when source = 'Android' then 1 else 0 end) > 0 and -- has Android
sum(case when source = 'Desktop' then 1 else 0 end) > 0 and -- has Desktop
sum(case when source not in ('Android', 'Desktop') then 1 else 0 end) = 0 -- has nothing else

Try this:
SELECT Id
FROM mytable
GROUP BY Id
HAVING COUNT(*) = COUNT(CASE WHEN Source='Android' THEN 1 END) +
COUNT(CASE WHEN Source='Desktop' THEN 1 END) AND
COUNT(CASE WHEN Source='Desktop' THEN 1 END) > 0 AND
COUNT(CASE WHEN Source='Android' THEN 1 END) > 0

Try this
select id from your_table
group by id
having
max(case when source in ('Android') then 1 else 0 end))=1
and
max(case when source in ('Desktop') then 1 else 0 end))=1
and count(distinct source)=2

Try to use
Select *
from yourtable a
where a.source = 'Android'
and not exist (Select b.id
from yourtable b
where b.id = a.id and b.source <> 'Android')

Related

SQL multiple conditions CASE WHEN and or

I have joined two tables (tbl1 and tbl2). AnimalNo is present in both tables, but it is the primary key of tbl1 and can occur multiple times in tbl2 (if the AnimalNo is associated with multiple ConditionID)
tbl1
AnimalNo | KillDate
1 | 01/01/2019
2 | 01/01/2019
3 | 01/01/2019
4 | 01/01/2020
5 | 01/01/2020
tbl2
AnimalNo | ConditionID
1 | 1
1 | 2
2 | 1
3 | 1
3 | 2
4 | 1
5 | 1
5 | 2
I would like a table where I get a count of the AnimalID which had each condition and the count of the AnimalNo which had both ConditionID 1 & 2, in the above example:
Year | N_killed | Type1 | Type2 | Both
2019 | 3 | 3 | 2 | 2
2020 | 2 | 2 | 1 | 1
I have this query which is successful at telling me the number of AnimalNo with each individual ConditionID but I would like to add the last column called Both which has a count of the AnimalNo which have both ConditionID 1 & 2
SELECT
DATEPART(year, tbl1.KillDate) AS KillYear,
COUNT(Distinct tbl1.AnimalNo) AS N_Killed,
COUNT(CASE WHEN tbl2.ConditionId =1 THEN 1 END) AS Type1,
COUNT(CASE WHEN tbl2.ConditionId =2 THEN 1 END) AS Type2
FROM tbl1 LEFT JOIN
tbl2 ON tbl1.AnimalNo = tbl2.AnimalNo
WHERE YEAR(tbl1.KillDate) >=2012
GROUP BY DATEPART(year, KillDate)
ORDER BY DATEPART(year, KillDate)
I think this is that you want
SELECT
DATEPART(year, tbl1.KillDate) AS KillYear,
COUNT(Distinct tbl1.AnimalNo) AS N_Killed,
COUNT(CASE WHEN tbl2.ConditionId =9 THEN 1 END) AS Type1a,
COUNT(CASE WHEN tbl2.ConditionId =75 THEN 1 END) AS Type1b,
COUNT(CASE WHEN tbl2.ConditionId =23 THEN 1 END) AS Type2a,
COUNT(CASE WHEN tbl2.ConditionId =81 THEN 1 END) AS Type2b,
COUNT(CASE WHEN tbl2.ConditionId IN (9,75) OR tbl2.ConditionId IN (23,81) BothTypes
FROM tbl1 LEFT JOIN
tbl2 ON tbl1.AnimalNo = tbl2.AnimalNo
WHERE YEAR(tbl1.KillDate) >=2012
GROUP BY DATEPART(year, KillDate)
ORDER BY DATEPART(year, KillDate)
Try this:
declare #tbl1 table
(
AnimalNo int
,KillDate date
)
insert into #tbl1(AnimalNo, KillDate)
select 1, '2019-01-01' union
select 2, '2019-01-01' union
select 3, '2019-01-01' union
select 4, '2020-01-01' union
select 5, '2020-01-01'
declare #tbl2 table
(
AnimalNo int
,ConditionID int
)
insert into #tbl2(AnimalNo, ConditionID)
select 1,1 union
select 1,2 union
select 2,1 union
select 3,1 union
select 3,2 union
select 4,1 union
select 5,1 union
select 5,2
select
year(k.KillDate) as [Year]
,count(distinct k.AnimalNo) as N_Killed
,sum(c.Type1)
,sum(c.Type2)
,sum(case when c.Type1 = 1 and c.Type2 = 1 then 1 else 0 end) as Both
from
#tbl1 k
JOIN
(
select
c.AnimalNo
,max(case when c.ConditionID = 1 then 1 else 0 end) as Type1
,max(case when c.ConditionID = 2 then 1 else 0 end) as Type2
from
#tbl2 c
group by c.AnimalNo
) c
on k.AnimalNo = c.AnimalNo
group by year(k.KillDate)

SQL Server Group By Combine Pivot Table Approaches

I have tables which designed like survey questions.
Answer table store like below. One answer related with three questions. QuestionId 1 and QuestionId 2 store Yes or No answers. If QuestionId 1 and QuestionId 2 both of them answer Yes, I want QuesiontId 3 to sum count with column value otherwise alias should be Others. Which approach is better , could u please help :)
AnswerId | QuestionId | QuestionOptionText
---------+------------+-------------------
1 | 1 | No
1 | 2 | No
1 | 3 | 0
--------------------------------------
2 | 1 | Yes
2 | 2 | No
2 | 3 | 0
--------------------------------------
3 | 1 | No
3 | 2 | Yes
3 | 3 | 1-10
--------------------------------------
4 | 1 | Yes
4 | 2 | Yes
4 | 3 | 1-10
--------------------------------------
5 | 1 | Yes
5 | 2 | Yes
5 | 3 | 11-20
Result should be like that
1-10 | 11-20 | Other
-----+-------+-------
1 | 1 | 3
I think you need a self join of the three types of question, and then the summing logic is easier. A different table structure would probably have simplified things. Normally you would have each question in a separate column.
select
sum(iif(ans1 = 'Yes' and ans2 = 'Yes' and ans3 = '1-10',1,0)) as '1-10',
sum(iif(ans1 = 'Yes' and ans2 = 'Yes' and ans3 = '11-20',1,0)) as '11-20',
sum(iif(ans1 <> 'Yes' or ans2 = 'Yes',1,0)) as 'other'
from (
select QuestionOptionText as ans1 from t where QuestionId = 1
) as a1
inner join (
select QuestionOptionText as ans2 from t where QuestionId = 2
) as a2
on a1.AnswerId = a2.AnswerId
inner join (
select QuestionOptionText as ans3 from t where QuestionId = 3
) as a3
on a1.AnswerId = a3.AnswerId
Is this what you want?
select sum(case when QuestionOptionText = '1-10' then 1 else 0 end),
sum(case when QuestionOptionText = '11-20' then 1 else 0 end),
sum(case when QuestionOptionText not in ('1-10', '11-20') then 1 else 0 end)
from t
where QuestionId = 3;
You could do this with two levels of aggregation. First compute the outcome of each series of answerId, the pivot the resultset:
select
sum(case when res = '1-10' then 1 else 0 end) res_1_10,
sum(case when res = '11-20' then 1 else 0 end) res_1_20,
sum(case when res = 'Other' then 1 else 0 end) res_other
from (
select
case when max(case when QuestionId in (1, 2) then QuestionOptionText end) = 'Yes'
then max(case when QuestionId = 3 then QuestionOptionText end)
else 'Other'
end res
from mytable
group by answerId
) t

SQL server Query for SUM group

I have table:
-------------------------------------
| Code | Name | Type | Qty |
-------------------------------------
| 0001 | Mouse | Purchase | 5 |
| 0002 | KeyBrd | Purchase | 8 |
| 0003 | Mouse | Sale | 2 |
-------------------------------------
i want to select them like this:
------------------------------------------------------------
| Code | Name | Total Purchase | Total Sale | Stock |
------------------------------------------------------------
| 0001 | Mouse | 5 | 2 | 3 |
| 0002 | KeyBrd | 8 | 0 | 8 |
------------------------------------------------------------
Im so confused, please help me with the query, thank you in advance
Try This
SELECT
Code,
Name,
TotalPurchase = SUM(CASE WHEN [Type] = 'Purchase' THEN Qty ELSE 0 END),
TotalSale = SUM(CASE WHEN [Type] = 'Sale' THEN Qty ELSE 0 END),
Stock = SUM(CASE WHEN [Type] = 'Purchase' THEN Qty ELSE 0 END) - SUM(CASE WHEN [Type] = 'Sale' THEN Qty ELSE 0 END)
FROM YourTable
group by Code,
Name
Conditional aggregation with the help of case expression is one approach
select min(Code) Code,
Name,
sum(case when Type = 'Purchase' then Qty else 0 end) [Total Purchase],
sum(case when Type = 'Sale' then Qty else 0 end) [Total Sale],
sum(case when Type = 'Purchase' then -Qty else Qty end) Stock
from table t
group by Name
We can also use like below.(Using Pivot) Please try this.
Data Generation
CREATE TABLE TableCase
(
Code VARCHAR(10)
,[Name] VARCHAR(10)
,[Type] VARCHAR(20)
,Qty INT
)
GO
INSERT INTO TableCase VALUES
('0001','Mouse' ,'Purchase',5),
('0002','KeyBrd' ,'Purchase',8),
('0003','Mouse' ,'Sale',2 )
GO
SOLUTION
SELECT MIN(Code) Code,[Name]
, ISNULL(SUM([Purchase]),0) [TotalPurchase]
, ISNULL(SUM([Sale]),0) TotalSale
, ISNULL(SUM([Purchase]),0) - ISNULL(SUM([Sale]),0) Stock
FROM TableCase
PIVOT
(
MAX(Qty) FOR [Type] IN ([Purchase],[Sale])
)t
GROUP By [Name]
ORDER BY [code]
OUTPUT
Code Name TotalPurchase TotalSale Stock
---------- ---------- ------------- ----------- -----------
0001 Mouse 5 2 3
0002 KeyBrd 8 0 8
(2 rows affected)

Rearranging a table in tsql

So I have a table with the following columns:
Type Test Min Max
-----------------------------
1 a 1 2
1 b Null Null
2 a 0 Null
2 b Null 1
Trying to get all of them like this
Type Test1 Test1 min Test1max Test2 Test2min Test2max
------------------------------------------------------------
1 a 1 2 b Null Null
2 a 0 Null b Null 1
Tried using unpivot first before I use pivot but it's still giving duplicate tests and removing null any help with this is much appreciated
Need null values to show up as well
Select type, result
(
From
Select type, min
From table t
)
Unpivot
(result for minmax in (min1)
)
Select
Thanks
using row_number() and conditional aggregation:
select
[Type]
, Test_1 = max(case when rn = 1 then Test end)
, Test_1_Min = max(case when rn = 1 then Min end)
, Test_1_Max = max(case when rn = 1 then Max end)
, Test_2 = max(case when rn = 2 then Test end)
, Test_2_Min = max(case when rn = 2 then Min end)
, Test_2_Max = max(case when rn = 2 then Max end)
from (
select *
, rn = row_number() over (partition by [Type] order by [Test])
from t
) as s
group by s.Type
rextester demo: http://rextester.com/BKL48976
returns:
+------+--------+------------+------------+--------+------------+------------+
| Type | Test_1 | Test_1_Min | Test_1_Max | Test_2 | Test_2_Min | Test_2_Max |
+------+--------+------------+------------+--------+------------+------------+
| 1 | a | 1 | 2 | b | NULL | NULL |
| 2 | a | 0 | NULL | b | NULL | 1 |
+------+--------+------------+------------+--------+------------+------------+
select *
from table t1
join table t2
on t1.type = t2.type
and t1.test < t2.test

Count and Group By for products sold

I have a table Transaction & a table product as below .
Each Transaction has multiple products.
ProductId Name
1 ABC
2 DEF
3 GHI
Each transaction can have multiple products sold.
TransactionId ProductSoldInDept1 ProductSoldinDept2 ProductSoldinDept3
1 1 null null
2 1 2 null
3 3 1 null
4 2 3 1
I am planning to generate a report and I would like to get a result something like this :
This shows the number of products sold per each department grouped by Id
Expected Result :
ProductID Department1ProdCount Department2ProdCount Department3ProdCount
1 2 1 1
2 1 1 0
3 1 1 0
I could get till here , this is a query to get the counts for one specific product
which is productid : 1
I would like to know how I could use a group by here :
select Count(CASE WHEN ProductSoldInDept1 = 1 THEN 1 END) ,
Count(CASE WHEN ProductSoldInDept2 = 1 THEN 1 END) ,
Count(CASE WHEN ProductSoldInDept3 = 1 THEN 1 END)
from Table1
SELECT
p.ProductID,
Dept1ProdCount = COUNT(CASE WHEN t.ProductSoldInDept1 = p.ProductID THEN 1 END),
Dept2ProdCount = COUNT(CASE WHEN t.ProductSoldInDept2 = p.ProductID THEN 1 END),
Dept3ProdCount = COUNT(CASE WHEN t.ProductSoldInDept3 = p.ProductID THEN 1 END)
FROM dbo.Product AS p
LEFT OUTER JOIN dbo.[Transaction] AS t
ON p.ProductID IN
(t.ProductSoldInDept1, t.ProductSoldinDept2, t.ProductSoldinDept3)
GROUP BY p.ProductID;
Result
| PRODUCTID | DEPT1PRODCOUNT | DEPT2PRODCOUNT | DEPT3PRODCOUNT |
----------------------------------------------------------------
| 1 | 2 | 1 | 1 |
| 2 | 1 | 1 | 0 |
| 3 | 1 | 1 | 0 |
See a demo
Try this
select ProductID,
v.Department1ProdCount, v.Department2ProdCount, v.Department3ProdCount
from product a
cross apply
(
select Count(CASE WHEN ProductSoldInDept1 = a.ProductID THEN 1 END) Department1ProdCount,
Count(CASE WHEN ProductSoldInDept2 = a.ProductID THEN 1 END) Department2ProdCount,
Count(CASE WHEN ProductSoldInDept3 = a.ProductID THEN 1 END) Department3ProdCount
from Table1
) v
This:
TransactionId ProductSoldInDept1 ProductSoldinDept2 ProductSoldinDept3
1 1 null null
2 1 2 null
3 3 1 null
4 2 3 1
might be better structured as this:
transid prodsold deptid
1 1 1
2 1 1
2 2 2
3 3 1
3 1 2
4 2 1
4 3 2
4 1 3
I think that would make your queries easier to write.

Resources