how to get flag values based on conditions in sql server - sql-server

I have a question about SQL Server: how to get flag values based on pid?
If name values A and Name value B corresponding id values is 1 then flag 1 other wise 0
CREATE TABLE [dbo].[TABLECHECK]
(
[ID] [INT] NULL,
[NAME] [VARCHAR](50) NULL,
[PID] [INT] NULL
) ON [PRIMARY]
GO
INSERT INTO [dbo].[TABLECHECK] ([ID], [NAME], [PID])
VALUES (1, N'A', 1), (0, N'B', 1), (1, N'A', 2),
(1, N'B', 2), (0, N'A', 3), (0, N'B', 3)
Based on this data, I want to get an output like this:
PID | Flag
-----+-------
1 | 0
2 | 1
3 | 0
My query:
select
pid, count(id),
case
when name in ('a', 'b') and id = 1
then 1
else 0
end
from
[TABLECHECK]
group by
pid
This query is resulting in an error.
Please tell me how to achieve this task in SQL Server.

If A & B always exists per PID, you can do this
SELECT PID,
Flag = CASE WHEN MIN(ID) = 1 THEN 1 ELSE 0 END
FROM TABLECHECK
GROUP BY PID

Since you are using SQL Server 2012, you can use MIN(), IIF() and GROUP BY
SELECT PID,
IIF(MIN(ID) = 1, 1, 0) Flag
FROM TABLECHECK
GROUP BY PID;

Related

How to calculate time difference on column value change?

I am trying to write a query to get the accumulated time difference with respect to a value change in a column in SQL Server 2012.
I am trying to gather some analytics on how much time a task was pending on another user, in this task there are 2 participants Role = 0 is the implementer and Role = 1 is the reviewer of the task. Through the duration of the task the implementer and the the reviewer can perform activities on the task multiple times. The aim is to to get the total time it was pending for the reviewer and the implementer.
To re create a snapshot of the data please see the example below
CREATE TABLE ActivityTable
([Id] [int] IDENTITY(1,1) NOT NULL,
[RoleId] [int] NULL,
[ActivityDate] [DATETIME] NULL)
INSERT INTO [ActivityTable] VALUES (1, '2018-10-19 13:00:19.840')
INSERT INTO [ActivityTable] VALUES (1, '2018-10-19 13:00:18.073')
INSERT INTO [ActivityTable] VALUES (1, '2018-10-19 12:59:48.417')
INSERT INTO [ActivityTable] VALUES (0, '2018-10-15 13:48:00.557')
INSERT INTO [ActivityTable] VALUES (0, '2018-10-15 12:56:25.567')
INSERT INTO [ActivityTable] VALUES (0, '2018-10-15 12:56:09.967')
INSERT INTO [ActivityTable] VALUES (0, '2018-10-15 12:55:26.500')
INSERT INTO [ActivityTable] VALUES (0, '2018-10-15 12:53:17.997')
INSERT INTO [ActivityTable] VALUES (1, '2018-10-15 12:36:17.967')
INSERT INTO [ActivityTable] VALUES (1, '2018-10-15 12:35:38.497')
INSERT INTO [ActivityTable] VALUES (1, '2018-10-15 12:33:05.860')
INSERT INTO [ActivityTable] VALUES (1, '2018-10-15 12:32:07.793')
INSERT INTO [ActivityTable] VALUES (1, '2018-10-15 12:32:00.010')
INSERT INTO [ActivityTable] VALUES (0, '2018-10-15 12:18:18.417')
INSERT INTO [ActivityTable] VALUES (0, '2018-10-15 12:17:16.370')
INSERT INTO [ActivityTable] VALUES (0, '2018-10-15 12:11:48.590')
INSERT INTO [ActivityTable] VALUES (0, '2018-10-15 11:58:38.557')
INSERT INTO [ActivityTable] VALUES (0, '2018-10-15 11:56:23.820')`
So the total time for each transition would look like
RoleInfo Start Time End Time Duration Minutes
0 2018-10-15 11:56:23.820 2018-10-15 12:32:00.010 37
1 2018-10-15 12:32:00.010 2018-10-15 12:53:17.997 22
0 2018-10-15 12:53:17.997 2018-10-19 12:59:48.417 5767
1 2018-10-19 12:59:48.417 2018-10-19 13:00:19.840 1
and the final result expected is aggregation of pending times
RoleInfo Duration in Minutes
0 5804
1 23
refer to comments within the query.
execute each inner query by itself to see the result for better understanding
select RoleId, Duration = sum(datediff(minute, StartTime, EndTime))
from
(
-- perform a group by RoleId + grp
-- min() and max() on ActivityDate will gives you based on RoleId
-- however you wanted the StartTime of next RoleId. For this LEAD() OVER() is used
select RoleId,
StartTime = min(ActivityDate),
EndTime = coalesce(lead(min(ActivityDate)) over (order by min(ActivityDate)),
max(ActivityDate))
from
(
-- identify the group. each group is continuous same RoleId value
select *, grp = Id - dense_rank() over (partition by RoleId
order by ActivityDate desc)
from ActivityTable
) a
group by RoleId, grp
) b
group by RoleId
by the way, i think the expected result that you posted is wrong
/* RESULT
RoleId Duration
0 5802
1 22
*/

How to combine multiple rows in T-SQL

Using SQL Server 2012: I have a simple table:
CREATE TABLE simpletable
(
[key] INT NOT NULL IDENTITY(1,1),
[id] INT,
[ca] INT,
[cp] INT,
[ct] INT
)
For various reasons this table only has a single row per [ca], [cp] and [ct] - like this:
INSERT INTO simpletable ([id], [ca], [cp], [ct])
VALUES (1, 10, null, null),
(1, null, 20, null),
(1, null, 120, null),
(1, null, null, 30),
(2, 11, null, null),
(2, null, 21, null),
(2, null, null, 31),
(2, null, null, 231)
What I would like to achieve (without cursors) is to explode out all the combinations into a temp table or a table-type variable; something like this:
id ca cp ct
---------------
1 10 20 30
1 10 120 30
2 11 21 31
2 11 21 231
I'd really appreciate your help on this.
Here is one (Cumbersome) way to do it:
SELECT dca.[id], dca.[ca], dcp.[cp], dct.[ct]
FROM
(
SELECT [id], [ca]
FROM simpletable
WHERE [ca] IS NOT NULL
) dca
INNER JOIN
(
SELECT [id], [cp]
FROM simpletable
WHERE [cp] IS NOT NULL
) dcp ON dca.id = dcp.id
INNER JOIN
(
SELECT [id], [ct]
FROM simpletable
WHERE [ct] IS NOT NULL
) dct ON dca.id = dct.id
See a live demo on rextester
Note this solution is based on the assumption that there must be at least one column other then id that is not null in every row.

Hate to ask but does this script run on SQL Server 2008

Declare #Table table (RowNumber int, Increment int, Score int)
Insert into #Table
values (1, 1, NULL), (2, 100000, NULL), (3, -1, NULL),
(4, 1, NULL), (5, 10, NULL), (6, -1, NULL),
(7, -100000, NULL), (8, -10, NULL)
Update #Table
Set Score = B.Score
From #Table A
Join (Select RowNumber, Score = sum(Increment) over (Order By RowNumber)
from #Table) B on A.RowNumber = B.RowNumber
Select * from #Table
Returns
RowNumber Increment score
1 1 1
2 100000 100001
3 -1 100000
4 1 100001
5 10 100011
6 -1 100010
7 -100000 10
8 -10 0
I have just updated your UPDATE statement ,Try it this gives expected result as you describe in your question
UPDATE #Table SET Score=(SELECT SUM(Increment)
FROM #Table B
WHERE b.RowNumber <= A.RowNumber)
FROM #Table A
The answer to the original question is: No.
This query doesn't run on SQL Server 2008.
Cumulative SUM was implemented only in SQL Server 2012. The ORDER BY in the OVER clause for the SUM.
sum(SomeColumn) over (Order By SomeColumn)
You will get this cryptic error message:
Msg 11305, Level 15, State 10, Line 11
The Parallel Data Warehouse
(PDW) features are not enabled.
It will run on SQL Server 2012+ even with compatibility level set to SQL Server 2008 (100).

T-SQL hierarchy - get breadcrumbs using query

I have virtual folder structure saved in database and I want to get the breadcrumbs from the current folder to the root. The data can be unsorted (but better will be sorted) and I want the parent folders of the current folder only.
The table definition is:
DECLARE Folders TABLE (
FOL_PK INT IDENTITY(1,1) NOT NULL,
FOL_Name VARCHAR(200) NOT NULL,
FOL_FOL_FK INT NULL -- Foreign key to parent
)
And this is my solution:
DECLARE #FOL_PK INT = 5 -- Current folder PK
DECLARE #breadcrumbs TABLE (
FOL_PK INT NOT NULL,
FOL_Name VARCHAR(200) NOT NULL,
FOL_FOL_FK INT NULL
)
DECLARE #isRoot BIT = 0
,#currentFolderPK INT
,#parentFK INT
-- Get current and parent folder PK
SELECT
#currentFolderPK = FOL_PK
FROM
Folder
WHERE
FOL_PK = #FOL_PK
-- Breadcrumb
WHILE (#isRoot = 0)
BEGIN
-- Save to breadcrumb
INSERT INTO #breadcrumbs
SELECT
FOL_PK,
FOL_Name,
FOL_FOL_FK
FROM
Folder
WHERE
FOL_PK = #currentFolderPK
-- Set parent as current
SET #currentFolderPK =
(
SELECT
FOL_FOL_FK
FROM
Folder
WHERE
FOL_PK = #currentFolderPK
)
-- Set flag for loop
SET #isRoot = CASE
WHEN ISNULL(#currentFolderPK, 0) = 0 THEN 1
ELSE 0
END
END
-- Return breadcrumbs
SELECT
FOL_PK AS PK,
FOL_Name AS Name,
FOL_FOL_FK AS ParentFK
FROM
#breadcrumbs
The problem is I am not very comfortable with the loop. Is there any other sophisticated solution how to do this?
Try this using a recursive Common Table Expression (CTE):
SQL Fiddle
MS SQL Server 2008 Schema Setup:
CREATE TABLE [Folders](
[FOL_PK] [int] IDENTITY(1,1) NOT NULL,
[FOL_Name] [varchar](200) NOT NULL,
[FOL_FOL_FK] [int] NULL,
CONSTRAINT [PK__Folders__FOL_PK] PRIMARY KEY CLUSTERED
(
[FOL_PK] ASC
))
ALTER TABLE [dbo].[Folders]
WITH CHECK ADD CONSTRAINT [FK_Folders_Folders] FOREIGN KEY([FOL_FOL_FK])
REFERENCES [dbo].[Folders] ([FOL_PK])
ALTER TABLE [dbo].[Folders] CHECK CONSTRAINT [FK_Folders_Folders]
INSERT INTO Folders(FOL_Name, FOL_FOL_FK)
VALUES ('Level 1', NULL),
('Level 1.1', 1),
('Level 1.2', 1),
('Level 1.3', 1),
('Level 1.2.1', 3),
('Level 1.2.2', 3),
('Level 1.2.3', 3),
('Level 1.2.2.1', 6),
('Level 1.2.2.2', 6),
('Level 1.2.2.3', 6),
('Level 1.3.1', 4),
('Level 1.3.2', 4)
Query 1:
DECLARE #FolderId Int = 9
;WITH CTE
AS
(
SELECT FOL_PK AS PK, FOL_NAME As Name, FOL_FOL_FK AS ParentFK
FROM Folders
WHERE FOL_PK = #FolderId
UNION ALL
SELECT F.FOL_PK AS PK, F.FOL_NAME AS Name, F.FOL_FOL_FK AS ParentFK
FROM Folders F
INNER JOIN CTE C
ON C.ParentFK = F.FOL_PK
)
SELECT *
FROM CTE
Results:
| PK | Name | ParentFK |
|----|---------------|----------|
| 9 | Level 1.2.2.2 | 6 |
| 6 | Level 1.2.2 | 3 |
| 3 | Level 1.2 | 1 |
| 1 | Level 1 | (null) |

SQL Server: How to write a query to select id having all values less than 0(zero)

Consider the following table,
Table 1:
id (int): 1 1 2 2 2
value (int): -1 0 -1 -3 -8
How to write a query to select the id from the table which has all the values of column value less than 0?
Try this one -
DECLARE #temp TABLE
(
id INT,
value INT
)
INSERT INTO #temp (id, value)
VALUES (1, -1), (1, 0), (2, -1), (2, -3), (2, -8)
SELECT id
FROM #temp
GROUP BY id
HAVING MAX(value) < 0
Output -
id
-----------
2

Resources