Select All rows in when count(*) = count(IDField) - sql-server

I have this table in SQL Server 2008.
id | TaskID | TaskHours
------------------------
0 | 25 | 1
1 | 25 | 0
2 | 24 | 1
3 | 24 | 2
4 | 24 | 2
5 | 23 | 0
I want to know how to select all by TaskID where the TaskHours all have a value > 0. I also want to select all rows by TaskID where the TaskHours have a 0 in them.
Basically I want to know if a task is completed by giving me all rows.
so Completed Tasks should show
id | TaskID | TaskHours
------------------------
2 | 24 | 1
3 | 24 | 2
4 | 24 | 2
and non completed tasks should show
id | TaskID | TaskHours
------------------------
0 | 25 | 1
1 | 25 | 0
5 | 23 | 0
I've tried
select * from tblTasks where TaskHours > 0
but I got this and I don't want 25 because it has a 0.
id | TaskID | TaskHours
------------------------
0 | 25 | 1
2 | 24 | 1
3 | 24 | 2
4 | 24 | 2
I've tried count(*) and count(Taskhours) > 0 but I couldn't get any further.
Any ideas?

For both queries, you may use exists logic. For the first query, consider:
SELECT t1.id, t1.TaskID, t1.TaskHours
FROM tblTasks t1
WHERE NOT EXISTS (SELECT 1 FROM tlbTasks t2
WHERE t2.TaskID = t1.TaskID AND t2.TaskHours = 0);
And for all tasks which have at least one record with zero task hours:
SELECT t1.id, t1.TaskID, t1.TaskHours
FROM tblTasks t1
WHERE EXISTS (SELECT 1 FROM tlbTasks t2
WHERE t2.TaskID = t1.TaskID AND t2.TaskHours = 0);

You can use CTE(Common Table expressions) together with NOT EXISTS, EXISTS clause to derive the results.
DECLARE #tasks TABLE(id int, taskid int, taskhours int)
INSERT INTO #tasks
values
(0 , 25 , 1),
(1 , 25 , 0),
(2 , 24 , 1),
(3 , 24 , 2),
(4 , 24 , 2),
(5 , 23 , 0);
;WITH CTE_TasksCompleted AS
(
SELECT DISTINCT TaskId FROM #tasks
WHERE taskhours = 0
)
-- Completed Tasks
SELECT ot.* FROM #tasks as ot
WHERE Not exists (SELECT TaskId from CTE_TasksCompleted
WHERE taskId = ot.taskId)
;WITH CTE_TasksCompleted AS
(
SELECT DISTINCT TaskId FROM #tasks
WHERE taskhours = 0
)
-- NotCompleted Tasks
SELECT ot.* FROM #tasks as ot
WHERE exists (SELECT TaskId from CTE_TasksCompleted
WHERE taskId = ot.taskId)
Completed Tasks
+----+--------+-----------+
| id | taskid | taskhours |
+----+--------+-----------+
| 2 | 24 | 1 |
| 3 | 24 | 2 |
| 4 | 24 | 2 |
+----+--------+-----------+
Not Completed Tasks
+----+--------+-----------+
| id | taskid | taskhours |
+----+--------+-----------+
| 0 | 25 | 1 |
| 1 | 25 | 0 |
| 5 | 23 | 0 |
+----+--------+-----------+

Related

Child record re-numbering per parent record

I have a parent and child table like the following:
Parent Table
CourseId | CourseName
1 | MVC training
and the
Child Table
Id | StudentId | CourseId | AttnDate
1 | 33 | 1 | 6/1/2019
2 | 33 | 1 | 6/2/2019
3 | 33 | 1 | 6/3/2019
4 | 34 | 1 | 6/1/2019
5 | 34 | 1 | 6/2/2019
6 | 34 | 1 | 6/3/2019
I searched over google to use rownumber to make this but could not make it.
No idea
I want the final result like the following table. What I need is to change the 33 to 1 and 34 to 2:
Id | StudentId | CourseId | AttnDate
1 | 1 | 1 | 6/1/2019
2 | 1 | 1 | 6/2/2019
3 | 1 | 1 | 6/3/2019
4 | 2 | 1 | 6/1/2019
5 | 2 | 1 | 6/2/2019
6 | 2 | 1 | 6/3/2019
Try this using DENSE_RANK()
SELECT Id,
DENSE_RANK()OVER( ORDER BY StudentId) AS StudentId,
CourseId,
AttnDate
FROM Parent p
INNER JOIN Child c ON c.CourseId = p.CourseId
ORDER bY p.ID
Why do you need to "change the 33 to 1 and 34 to 2"? Is it for the purpose of assigning unique rank number for each distinct row within the partition (data grouped by StudentId)?
If it's true, then SQL Server DENSE_RANK ranking function is what you need
SELECT *,
DENSE_RANK() OVER(ORDER BY c.StudentId) AS RowNumberRank -- here is your rank number (StudentId in your final result)
FROM Child c

How to combine multiple rows into one row and multiple column in SQL Server?

I have different tables through I made temp table and here is the result set of temp table:
car_id | car_type | status | count
--------+----------+---------+------
100421 | 1 | 1 | 9
100421 | 1 | 2 | 8
100421 | 1 | 3 | 3
100421 | 2 | 1 | 6
100421 | 2 | 2 | 8
100421 | 2 | 3 | 3
100422 | 1 | 1 | 5
100422 | 1 | 2 | 8
100422 | 1 | 3 | 7
Here is the meaning of status column:
1 as sale
2 as purchase
3 as return
Now I want to show this result set as below
car_id | car_type | sale | purchase | return
--------+----------+------+----------+----------
100421 | 1 | 9 | 8 | 3
100421 | 2 | 6 | 8 | 3
100422 | 1 | 5 | 8 | 7
I tried but unable to generate this result set. Can anyone help?
You can also use a CASE expression.
Query
select [car_id], [car_type],
max(case [status] when 1 then [count] end) as [sale],
max(case [status] when 2 then [count] end) as [purchase],
max(case [status] when 3 then [count] end) as [return]
from [your_table_name]
group by [car_id], [car_type]
order by [car_id];
Try this
select car_id ,car_type, [1] as Sale,[2] as Purchase,[3] as [return]
from (select car_id , car_type , [status] ,[count] from tempTable)d
pivot(sum([count]) for [status] in([1],[2],[3]) ) as pvt
also you can remove the subquery if you don't have any condition
like
select car_id ,car_type, [1] as Sale,[2] as Purchase,[3] as [return]
from tempTable d
pivot(sum([count]) for [status] in([1],[2],[3]) ) as pvt

Remove cursur SQL statement

I want to remove a cursor in SQL, to increase performance (and because I want to learn how to use best practice and best practice is supposed to be set based, without cursor).
Anyway, I have a temp table that looks like this:
+------------+--------+-------+----+
| Period | Change | Value | NR |
+------------+--------+-------+----+
| 201705 | 7 | 26055 | 1 |
| 201704 | 29 | 0 | 2 |
| 201703 | -92 | 0 | 3 |
| 201702 | -338 | 0 | 4 |
| 201701 | 81 | 0 | 5 |
| 201612 | 107 | 0 | 6 |
| 201611 | 72 | 0 | 7 |
| 201610 | 54 | 0 | 8 |
| 201609 | 64 | 0 | 9 |
| 201608 | 47 | 0 | 10 |
| 201607 | 23 | 0 | 11 |
| 201606 | 45 | 0 | 12 |
+------------+--------+-------+----+
Currently, the Cursor acts as follows:
DECLARE #Value INT
BEGIN
DECLARE c_Value CURSOR FOR
SELECT NR
FROM ##TMP
WHERE Value = 0
----
OPEN c_Value
FETCH NEXT FROM c_Value
INTO #Value
WHILE ##FETCH_STATUS = 0
BEGIN
SELECT #Value = Value - Change
FROM ##TMP
WHERE NR = (Select MAX(NR) From ##TMP WHERE Value <> 0)
BEGIN
UPDATE ##TMP
SET Value = #Value
WHERE NR = (Select MAX(NR)+1 From ##TMP WHERE Value <> 0)
END
FETCH NEXT FROM c_Value
INTO #Value
END
CLOSE c_Value
DEALLOCATE c_Value
END
Result:
+------------+--------+-------+----+
| Period | Change | Value | NR |
+------------+--------+-------+----+
| 201705 | 7 | 26055 | 1 |
| 201704 | 29 | 26048 | 2 |
| 201703 | -92 | 26019 | 3 |
| 201702 | -338 | 26111 | 4 |
| 201701 | 81 | 26449 | 5 |
| 201612 | 107 | 26368 | 6 |
| 201611 | 72 | 26261 | 7 |
| 201610 | 54 | 26189 | 8 |
| 201609 | 64 | 26135 | 9 |
| 201608 | 47 | 26071 | 10 |
| 201607 | 23 | 26024 | 11 |
| 201606 | 45 | 26001 | 12 |
+------------+--------+-------+----+
So, how can I achieve this result, without the use of a cursor? I tried it with a CTE, but I can not get this result.
First you need get the starting value.
SELECT [Value] as StartValue
FROM Table1
WHERE NR = 1
Then using cumulative SUM() you can modify the starting Value, notice you have to ignore the [Change] value for each row
SQL DEMO
WITH CTE as (
SELECT [Value] as StartValue
FROM Table1
WHERE NR = 1
)
SELECT T.*,
- SUM(CHANGE) OVER (ORDER BY [NR])
+ [CHANGE] as TotalChange, -- just for debug, dont need this.
CTE.StartValue
- SUM([CHANGE]) OVER (ORDER BY [NR])
+ [CHANGE] as NewValue
FROM Table1 T
CROSS JOIN CTE
OUTPUT
SQL Server 2012 or higher:
CREATE TABLE ##TMP (
Period int
,Change float
,Value float
,Nr int
);
INSERT INTO ##TMP VALUES
(201705, 7 , 26055, 1)
,(201704, 29 , 0, 2)
,(201703, -92 , 0, 3)
,(201702, -338 , 0, 4)
,(201701, 81 , 0, 5)
,(201612, 107 , 0, 6)
,(201611, 72 , 0, 7)
,(201610, 54 , 0, 8)
,(201609, 64 , 0, 9)
,(201608, 47 , 0,10)
,(201607, 23 , 0,11)
,(201606, 45 , 0,12)
;with cte as (
SELECT Period, Change, value as Value_Org, Nr, SUM(Value - Change) OVER (ORDER BY Nr ASC ) as Value
FROM ##TMP
)
select a.Period, a.Change, a.nr, a.value_org, a.value, b.value,
isnull(b.value, a.value_org)
from cte as a
left outer join cte as b
on a.nr = b.nr+1
order by a.Nr
This can be solved by using the windowing functions introduced in SQL Server 2014.
select period,
change,
NR = Row_Number() Over(Order by period),
Value = Sum(Change) Over(Order by period rows unbounded preceding)
This was freehand and may not parse, but should get you close enough.

SQL Server query for next row value where previous row value

This query gives me Event values from 1 to 20 within an hour, how to add to that if a consecutive Event value is >=200 as well?
SELECT ID, count(Event) as numberoftimes
FROM table_name
WHERE Event >=1 and Event <=20
GROUP BY ID, DATEPART(HH, AtHour)
HAVING DATEPART(HH, AtHour) <= 1
ORDER BY ID desc
In this dummy 24h table:
+----+-------+--------+
| ID | Event | AtHour |
+----+-------+--------+
| 1 | 1 | 11:00 |
| 1 | 4 | 11:01 |
| 1 | 1 | 11:02 |
| 1 | 20 | 11:03 |
| 1 | 200 | 11:04 |
| 1 | 1 | 13:00 |
| 1 | 1 | 13:05 |
| 1 | 2 | 13:06 |
| 1 | 500 | 13:07 |
| 1 | 39 | 13:10 |
| 1 | 50 | 13:11 |
| 1 | 2 | 13:12 |
+----+-------+--------+
I would like to select IDs with Event with values with range between 1 and 20 followed immediately by value greater than or equal to 200 within an hour.
Expected result should be something like that:
+----+--------+
| ID | AtHour |
+----+--------+
| 1 | 11 |
| 1 | 13 |
| 2 | 11 |
| 2 | 14 |
| 3 | 09 |
| 3 | 12 |
+----+--------+
or just how many times it has happened for unique ID instead of which hour.
Please excuse me I am still rusty with post formatting!
CREATE TABLE data (Id INT, Event INT, AtHour SMALLDATETIME);
INSERT data (Id, Event, AtHour) VALUES
(1,1,'2017-03-16 11:00:00'),
(1,4,'2017-03-16 11:01:00'),
(1,1,'2017-03-16 11:02:00'),
(1,20,'2017-03-16 11:03:00'),
(1,200,'2017-03-16 11:04:00'),
(1,1,'2017-03-16 13:00:00'),
(1,1,'2017-03-16 13:05:00'),
(1,2,'2017-03-16 13:06:00'),
(1,500,'2017-03-16 13:07:00'),
(1,39,'2017-03-16 13:10:00')
;
; WITH temp as (
SELECT rownum = ROW_NUMBER() OVER (PARTITION BY id ORDER BY AtHour)
, *
FROM data
)
SELECT a.id, DATEPART(HOUR, a.AtHour) as AtHour, COUNT(*) AS NumOfPairs
FROM temp a JOIN temp b ON a.rownum = b.rownum-1
WHERE a.Event BETWEEN 1 and 20 AND b.Event >= 200
AND DATEDIFF(MINUTE, a.AtHour, b.AtHour) <= 60
GROUP BY a.id, DATEPART(HOUR, a.AtHour)
;

Sql query to check if a certain value appears more than once in rows

I have table with 5 columns like this
+----+-------------------------+-----------+--------+-----------+
| Id | CreateDate | CompanyId | UserId | IsEnabled |
+----+-------------------------+-----------+--------+-----------+
| 1 | 2016-01-02 23:40:46.517 | 1 | 1 | 1 |
| 2 | 2016-01-16 00:07:59.857 | 1 | 2 | 1 |
| 3 | 2016-01-25 15:17:54.420 | 3 | 3 | 1 |
| 25 | 2016-03-07 16:48:39.260 | 24 | 10 | 0 |
| 26 | 2016-03-07 16:48:39.263 | 25 | 2 | 0 |
+----+-------------------------+-----------+--------+-----------+
(thanks http://www.sensefulsolutions.com/2010/10/format-text-as-table.html for ASCII table!)
I'm trying to check if a UserId is recorded for more than one CompanyId's.
So far I managed to check if a UserId happens to appear more than one by using this query
WITH T AS
(
SELECT * ,
Count(*) OVER (PARTITION BY UserId) as Cnt
From CompanyUser
)
select Distinct UserId
FROM T
Where Cnt >1
It returns 2 correctly.
Where I'm stuck is, how can I parameterize the UserId and check if an Id is recorded for more than one company.
Declare #UserID as bigint
Set #UserID = 2
select Distinct Count(CompanyID)
FROM ComapynUser
Where UserId = #UserId
I think this gives you what you need.

Resources