Hide rows when column values are duplicate - sql-server

I have a table named "letters" with two columns looking like this:
case_nr | date
--------+-----------------------
1 | 2015-06-13 12:45:04
1 | NULL
2 | 2015-06-11 12:45:09
3 | 2015-06-12 17:41:49
3 | 2015-06-13 18:42:99
case_nr 1 have printed 2 letters but only one was sent
I want to filter all cases where all letters was sent (have a date)
So in this case result should be:
2
3

You can use DISTINCT with NOT IN:
SELECT DISTINCT case_nr
FROM TableName
WHERE case_nr NOT IN
(SELECT case_nr FROM TableName WHERE [date] IS NULL )
Result:
case_nr
--------
2
3
Sample result in SQL Fiddle.

Group by the case_nr and take only those having no record with date is null
select case_nr
from your_table
group by case_nr
having sum(case when date is null then 1 else 0 end) = 0
SQLFiddle demo

As an alternative:
SELECT
case_nr
FROM (
SELECT
case_nr,
COUNT(CASE WHEN [date] IS NULL THEN 1 END) AS cnt
FROM
yourTable
GROUP BY
case_nr
) t
WHERE
cnt = 0

Related

Number rows based on id

I have a query that returns something like this:
Id | Value
1 | Hi,
1 | I'm
2 | just
2 | an
2 | example
3 | message.
What I want to do is number the rows based on the id. So with the example above, I want to return something like this:
Id | Value | Number
1 | Hi, | 1
1 | I'm | 2
2 | just | 1
2 | an | 2
2 | example | 3
3 | message. | 1
Is there a simple way to do this in the same query as the one you would use in the first example?
The problem is there is NOTHING in that table that guarantees the order of rows, so the result you want cannot be guaranteed.
select *
, row_number() over(partition by id order by (select 1)) as Number
from yourtable
You can make use of the rownumber function.
SELECT ROW_NUMBER OVER (PARTITION BY ID ORDER BY (SELECT 1)) AS RowNumb
You Can Use the ROW_NUMBER() Function and Partition by Id. Like this
DECLARE #MyTable AS TABLE
(
Id INT,
[Value] VARCHAR(50)
)
INSERT INTO #MyTable
(
Id,
[Value]
)
SELECT '1','Hi,' UNION
SELECT '1','I''m' UNION
SELECT '2','just' UNION
SELECT '2','an' UNION
SELECT '2','example' UNION
SELECT '3','message.'
SELECT
*,
Number = ROW_NUMBER() OVER(PARTITION BY Id ORDER BY Id)
FROM #MyTable
Result
Id Value Number
----------- -------------------------------------------------- --------------------
1 Hi, 1
1 I'm 2
2 an 1
2 example 2
2 just 3
3 message. 1
Please try following script.
DECLARE #MyTable AS TABLE
(
Id INT,
[Value] VARCHAR(50)
)
INSERT INTO #MyTable
(
Id,
[Value]
)
SELECT '1','Hi,' UNION
SELECT '1','I''m' UNION
SELECT '2','just' UNION
SELECT '2','an' UNION
SELECT '2','example' UNION
SELECT '3','message.'
select *, dense_rank()over(partition by Id order by Value) as Number from #MyTable
/*
Id Value Number
----------- -------------------------------------------------- --------------------
1 Hi, 1
1 I'm 2
2 an 1
2 example 2
2 just 3
3 message. 1
*/
Best Regards,
Rachel

SQL Server how to sum max for specific category?

Got a problem when constructing a analysis SQL using SQL Server
The raw data as below
GameID | UsrRegID | Score_User
281 | 1 | 1
281 | 1 | 2
281 | 1 | 3
282 | 1 | 0
282 | 1 | 0
282 | 1 | 1
283 | 1 | 2
283 | 1 | 3
Below is the expect output result:
Distinct_Count_GameID | UsrRegID | Score_User
3 | 1 | 7
The logic for calculating the Score_user as below:
Sum(Max(Score_user) for each GemeID)
So the result need to be 3+1+3=7.
Can using the pure SQL to get the above expecting output?
I think we need to aggregate twice here. One option uses ROW_NUMBER:
WITH cte AS (
SELECT GameID, UsrRegID, Score_User,
ROW_NUMBER() OVER (PARTITION BY GameID, UsrRegID ORDER BY Score_User DESC) rn
FROM yourTable
)
SELECT
UsrRegID,
COUNT(DISTINCT GameID) AS Distinct_Count_GameID,
SUM(Score_User) AS Score_User
FROM cte
WHERE rn = 1
GROUP BY
UsrRegID;
You can't do an aggregate of an aggregate on the same SELECT, you can chain them together with CTE or subqueries.
;WITH Maxs AS
(
SELECT
T.GameID,
T.UsrRegID,
MaxScore = MAX(T.Score_User)
FROM
YourTable AS T
GROUP BY
T.GameID,
T.UsrRegID
)
SELECT
M.UsrRegID,
Distinct_Count_GameID = COUNT(DISTINCT(M.GameID)),
Score_User = SUM(M.MaxScore)
FROM
Maxs AS M
GROUP BY
M.UsrRegID
You can also try like following.
SELECT Count(DISTINCT [rgameid]) Distinct_Count_GameID,
Count(DISTINCT [usrregid]) UsrRegID,
(SELECT Sum(M)
FROM (SELECT Max([score_user]) M
FROM [TableName]
GROUP BY [rgameid])t) AS Score_User
FROM [TableName]
DEMO
First find maximum value of score for each GameId and UsrRegID and then find SUM() for the column, Score_User and group it by the columns, GameID and UsrRegID using GROUP BY clause.
Query
select count(distinct [t].[GameID]) as [GameID], [t].[UsrRegID],
sum([t].[Score_User]) as [Score_User] from(
select [GameID], [UsrRegID], max([Score_User]) as [Score_User]
from [your_table_name]
group by [GameID], [UsrRegID]
) as [t]
group by [t].[UsrRegID];
Or, give a row number based on the descending order of score value and group by GameID and UsrRegID. Then find the count of distinct GameId and sum of maximum score.
Query
;with cte as(
select [rn] = row_number() over(
partition by [GameID], [UsrRegID]
order by [Score_User] desc
), *
from [your_table_name]
)
select count(distinct [GameID]) as [GameID], [UsrRegID],
sum([Score_User]) as [Score_User] from cte
where [rn] = 1
group by [UsrRegID];
Aggregates and a COUNT(Distinct GameID):
declare #raw as table (GameID int, UsrRegID int, Score_user int)
insert into #raw values (281, 1, 1)
,(281, 1, 2)
,(281, 1, 3)
,(282, 1, 0)
,(282, 1, 0)
,(282, 1, 1)
,(283, 1, 2)
,(283, 1, 3)
select count(distinct GameID) as Distinct_Count_GameID, UsrRegID, sum(max_score_user)
from
(
select GameID
, UsrRegID
, max(score_user) as max_score_user
from #raw
group by GameID, UsrRegID
) a
group by a.UsrRegID

Show multiple rows and columns using subquery under SELECT clause

I want to show the number of clerks and managers in each department.
Here is my code:
SELECT DISTINCT
deptno AS 'DEPARTMENT NUMBER',
(SELECT COUNT(*)
FROM EMP
WHERE JOB = 'CLERK'
GROUP BY DEPTNO) AS 'NUMBER OF CLERKS',
(SELECT COUNT(*)
FROM EMP
WHERE JOB = 'MANAGER'
GROUP BY DEPTNO) AS 'NUMBER OF MANAGER'
FROM
EMP
GROUP BY
deptno
Below is the error returned:
Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression.
I wanted to show the result like this:
+-------------------+------------------+---------------------+
| DEPARTMENT NUMBER | NUMBER OF CLERKS | NUUMBER OF MANAGERS |
+-------------------+------------------+---------------------+
| 10 | 1 | 1 |
| 20 | 2 | 1 |
| 30 | 1 | 1 |
+-------------------+------------------+---------------------+
This kind of calculation is usually easiest to do using sum + case with something like this:
SELECT
deptno,
sum (case when JOB = 'CLERK' then 1 else 0 end) AS [NUMBER OF CLERKS],
sum (case when JOB = 'MANAGER' then 1 else 0 end) AS [NUMBER OF MANAGERS]
FROM
EMP
GROUP BY
deptno
you can also do it using PIVOT
DECLARE #EMP table (Dep_No INT, Job VARCHAR(20))
INSERT INTO #EMP
VALUES (10,'clerk'),
(10,'clerk'),
(10,'clerk'),
(10,'Manager'),
(20,'clerk'),
(20,'clerk'),
(20,'clerk'),
(20,'clerk'),
(20,'clerk'),
(20,'clerk'),
(20,'Manager'),
(20,'Manager'),
(30,'clerk'),
(20,'Manager'),
(30,'clerk')
SELECT Dep_No , [clerk] Number_Of_Clerks ,[Manager] Number_of_Managers
FROM #EMP
PIVOT
(
COUNT(Job) FOR Job in ([clerk], [Manager])
) W

If Value is present in two consecutive months , display only one month in sql

I would want to check ID in consecutive months, IF Same ID is present in two consecutive months then consider that ID only for 1st month.
If ID's are not in consecutive month then show the distinct ID's grouped by start date month.(We consider only start date)
For example, ID 1 is present in start date months january and Feb , then Distinct count of this ID will be 1 in Jan, how ever ID 2 and 3 are
present in Jan and March and Feb and May Resp, now I would like to see this distinct count of ID in Jan and March.
Current Data
Table1:
ID StartDate EndDate
1 2017-01-12 2017-01-28
1 2017-01-19 2017-01-28
1 2017-01-29 2017-02-11
1 2017-02-01 2017-02-11
1 2017-02-19 2017-02-24
2 2017-01-12 2017-01-28
2 2017-01-19 2017-01-28
2 2017-03-09 2017-03-20
3 2017-02-12 2017-02-28
3 2017-02-19 2017-02-28
3 2017-05-05 2017-05-29
3 2017-05-09 2017-05-29
I tried with below logic bt I know I am missing on something here.
select t.* from Table1 t
join Table1 t t1
on t1.ID=t.ID
and datepart(mm,t.StartDate)<> datepart(mm,t1.StartDate)+1
Expected Result:
DistinctCount StartDateMonth(In Numbers)
1 1(Jan)
2 1(Jan)
2 3(March)
3 2(Feb)
3 5(May)
Any help is appreciated!
Here's my solution. The thinking for this is:
1) Round all the dates to the first of the month, then work with the distinct dataset of (ID, StartDateRounded). From your dataset, the result should look like this:
ID StartDateRounded
1 2017-01-01
1 2017-02-01
2 2017-01-01
2 2017-03-01
3 2017-02-01
3 2017-05-01
2) From this consolidated dataset, find all records by ID that do not have a record for the previous month (which means it's not a consecutive month and thus is a beginning of a new data point). This is your final dataset
with DatesTable AS
(
SELECT DISTINCT ID
,DATEADD(month,DateDiff(month,0,StartDate),0) StartDateRounded
,DATEADD(month,DateDiff(month,0,StartDate)+1,0) StartDateRoundedPlusOne
FROM Table1
)
SELECT t1.ID, DatePart(month,t1.StartDateRounded) AS StartDateMonth
FROM DatesTable t1
LEFT JOIN DatesTable t2
ON t1.ID = t2.ID
AND t1.StartDateRounded = t2.StartDateRoundedPlusOne
WHERE t2.ID IS NULL; --Verify no record exists for prior month
sqlfiddler for reference. Let me know if this helps
Just need to take advantage of the lag on the inner query to compare values between rows, and apply the logic in question on the middle query, and then do a final select.
/*SAMPLE DATA*/
create table #table1
(
ID int not null
, StartDate date not null
, EndDate date null
)
insert into #table1
values (1, '2017-01-12', '2017-01-28')
, (1, '2017-01-19', '2017-01-28')
, (1, '2017-01-29', '2017-02-11')
, (1, '2017-02-01', '2017-02-11')
, (1, '2017-02-19', '2017-02-24')
, (2, '2017-01-12', '2017-01-28')
, (2, '2017-01-19', '2017-01-28')
, (2, '2017-03-09', '2017-03-20')
, (3, '2017-02-12', '2017-02-28')
, (3, '2017-02-19', '2017-02-28')
, (3, '2017-05-05', '2017-05-29')
, (3, '2017-05-09', '2017-05-29')
/*ANSWER*/
--Final Select
select c.ID
, c.StartDateMonth
from (
--Compare record values to rule a record in/out based on OP's logic
select b.ID
, b.StartDateMonth
, case when b.StartDateMonth = b.StartDateMonthPrev then 0 --still the same month?
when b.StartDateMonth = b.StartDateMonthPrev + 1 then 0 --immediately prior month?
when b.StartDateMonth = 1 and b.StartDateMonthPrev = 12 then 0 --Dec/Jan combo
else 1
end as IncludeFlag
from (
--pull StartDateMonth of previous record into current record
select a.ID
, datepart(mm, a.StartDate) as StartDateMonth
, lag(datepart(mm, a.StartDate), 1, NULL) over (partition by a.ID order by a.StartDate asc) as StartDateMonthPrev
from #table1 as a
) as b
) as c
where 1=1
and c.IncludeFlag = 1
Output:
+----+----------------+
| ID | StartDateMonth |
+----+----------------+
| 1 | 1 |
| 2 | 1 |
| 2 | 3 |
| 3 | 2 |
| 3 | 5 |
+----+----------------+
Try the below query,
SELECT ID,MIN(YEARMONTH) AS YEARMONTH
FROM (
SELECT ID
,YEAR([StartDate])*100+MONTH([StartDate]) AS YEARMONTH
,LAG(YEAR([StartDate])*100+MONTH([StartDate]))
OVER(ORDER BY ID) AS PREVYEARMONTH
,ROW_NUMBER() OVER(ORDER BY ID) AS ROW_NO
FROM #Table1
GROUP BY ID,((YEAR([StartDate])*100)+MONTH([StartDate]))
) AS T
GROUP BY ID
,(CASE WHEN YEARMONTH - PREVYEARMONTH > 1 THEN ROW_NO ELSE 0 END)
ORDER BY ID
Output:
ID YEARMONTH
1 201701
2 201701
2 201703
3 201702
3 201705
Thank you all guys. most of the logic seemed to work..but I tried just with below one and I Was good with thiis.
SELECT t1.ID, DatePart(month,t1.Startdate) AS StartDateMonth
FROM DatesTable t1
LEFT JOIN DatesTable t2
ON t1.ID = t2.ID
AND DatePart(month,t1.Startdate) = DatePart(month,t2.Startdate)+1
WHERE t2.ID IS NULL;
Thanks again
Ok, I wrote my first query without checking, believed that will work correctly. This is my updated version, should be faster than other solutions
select
id
, min(st)%12 --this will return start month
, min(st)/12 + 1 --this will return year, just in case if you need it
from (
select
id, st, gr = st - row_number() over (partition by ID order by st)
from (
select
distinct ID, st = (year(StartDate) - 1) * 12 + month(StartDate)
from
#table2
) t
) t
group by id, gr

Right using of PIVOT-statement in SQL Server

I have an audit table, part of data is looked like:
Id ColumnName Value RowId
---------------------------------
1 EditCheckId 100 1
2 FieldData_Id 10 1
3 EditType 1 1
4 Outcome True 1
5 EditCheckId 200 2
6 FieldData_Id 20 2
7 EditType 2 2
8 Outcome False 2
9 EditCheckId 300 3
10 FieldData_Id 30 3
11 EditType 3 3
12 Outcome True 3
and I want to construct such table groupping data by RowId
EditCheck_Id FieldData_Id EditType Outcome
---------------------------------------------------
100 10 1 True
200 20 2 False
300 30 3 True
I've tried the query:
select [EditCHeck_Id], [FieldData_Id], [EditType], [Outcome]
from
(
select [ColumnName], [Value]
from Audit a
) as [SourceTable]
pivot
(
max([Value])
for [ColumnName] in ([EditCHeck_Id], [FieldData_Id], [EditType], [Outcome])
) as [PivotTable];
http://sqlfiddle.com/#!6/7af71/3
using PIVOT statement but there is only one row in answer. Where is my problem?
You'll need some value to GROUP BY to make each of the rows distinct. Typically, you would use a windowing function like row_number() to generate a unique sequenced number over your current columnname. You can alter your query to the following:
select
[EditCheckId],
[FieldData_Id],
[EditType],
[Outcome]
from
(
select [ColumnName], [Value],
rn = row_number() over(partition by ColumnName order by id)
from Audit a
) as [SourceTable]
pivot
(
max([Value])
for [ColumnName] in ([EditCheckId], [FieldData_Id], [EditType], [Outcome])
) as [PivotTable];
See SQL Fiddle with Demo.
You could also use an aggregate function with a CASE expression to get the final result:
select
max(case when ColumnName = 'EditCheckId' then value end) [EditCheckId],
max(case when ColumnName = 'FieldData_Id' then value end) [FieldData_Id],
max(case when ColumnName = 'EditType' then value end) [EditType],
max(case when ColumnName = 'Outcome' then value end) [Outcome]
from
(
select [ColumnName], [Value],
rn = row_number() over(partition by ColumnName order by id)
from Audit a
) d
group by rn;
See SQL Fiddle with Demo Both give the result:
| EDITCHECKID | FIELDDATA_ID | EDITTYPE | OUTCOME |
|-------------|--------------|----------|---------|
| 100 | 10 | 1 | True |
| 200 | 20 | 2 | False |
| 300 | 30 | 3 | True |
You need something to distinguish the output rows, like for example your RowId
pivot does the grouping for you like so:
select [RowID], [EditCheckId], [FieldData_Id], [EditType], [Outcome]
from
(
select [ColumnName], [Value], [RowId]
from Audit a
) as [SourceTable]
pivot
(
max([Value])
for [ColumnName] in ([EditCheckId], [FieldData_Id], [EditType], [Outcome])
) as [PivotTable];
edited Fiddle demo

Resources