My source events table looks like this:
The result set I need should not include the duplicated "OPEN" values (4, 5), and if possible, return the first occurrence only.
The closest I've been able to get is to group them by looking at answers discussing "gaps and islands" but I'm lost as to how to actually "eliminate" the unneeded rows.
https://dbfiddle.uk/4eIDDmXx
Rather than using gaps and islands, I'd suggest using a simple LAG to get the previous row's OpenOrClosed value - then check if that previous row's OpenOrClosed value is different from the current row's.
This involves a first SELECT to get all rows, with LAG to get the corresponding previous row's value - and then a second SELECT to filter out only those that are different.
See this db<>fiddle which was based on your original one.
SELECT [ID]
,[EventDateTime]
,[SourceEventID]
,[OpenOrClosed]
FROM
(SELECT [ID]
,[EventDateTime]
,[SourceEventID]
,[OpenOrClosed]
,LAG([OpenOrClosed], 1) OVER (ORDER BY ID) AS [LastOOC]
FROM [dbo].[test]
) AS SourceData
WHERE LastOOC IS NULL OR OpenOrClosed <> LastOOC
Results are as below
ID EventDateTime SourceEventID OpenOrClosed
1 2013-01-31 14:20:00.000 331832 OPEN
2 2013-04-18 14:44:00.000 338907 CLOSED
3 2013-04-19 15:30:00.000 341210 OPEN
6 2013-04-24 12:22:00.000 339250 CLOSED
7 2013-05-08 12:32:00.000 340281 OPEN
8 2013-05-08 12:33:00.000 340282 CLOSED
9 2013-05-08 12:34:00.000 340255 OPEN
Related
I have the following table structure and data:
Data is ordered ASC and for each Master Clear there's a subsequent Blend Closed. If there's no subsequent Blend Closed then it should receive NULL.
Now I'd like to get the following result:
Master Clear Blend Closed
2018-09-17 03:12:03 2018-09-17 10:00:03
2018-09-17 10:37:03 2018-09-18 01:05:02
2018-09-18 04:55:02 2018-09-18 21:51:00
2018-09-18 22:55:00 2018-09-19 03:02:01
. .
. .
. .
2018-09-23 20:10:56 NULL
This is getting pairs of rows and moving the Time column value to its appropriate Value column: Master Clear or Blend Closed.
I tried to get this data shape but couldn't by any means. Is there any way to achieve this output using T-SQL?
One option would be to assign a row number to each value group, then do a regular pivot query:
WITH cte AS (
SELECT *, ROW_NUMBER() OVER (PARTITION BY Value ORDER BY Time) rn
FROM [BUR_BLEND].[dbo].[BLEND_START_END_TIMES]
)
SELECT
MAX(CASE WHEN Value = 'Master Clear' THEN Time END) AS [Master Clear],
MAX(CASE WHEN Value = 'Blend Closed' THEN Time END) AS [Blend Closed]
FROM cte
GROUP BY rn
ORDER BY rn;
Demo
Note that this answer assumes that the Master Clear and Blend Closed records always come together in logical pairs, and that there are no gaps. If not, then we would have to do more work to generate your output.
I have a table that looks like this:
ID A B Count
-----------------
1 abc 0 1
2 abc 0 2
3 abc 1 1
4 xyz 1 1
5 xyz 1 2
6 xyz 1 3
7 abc 1 2
8 abc 0 3
The "Count" column is incremented by one in the next insertion depending on the value of fields "A" and "B". so for example, if the next record I want to insert is:
ID A B Count
-----------------
abc 0
The value of count will be 4.
I have been trying to find documentation about this, but I'm still quite lost in the MS SQL world! There must be a way to configure the "Count" column as a sequence dependent on the other two columns. My alternative would be to select all the records with A=abc and B=0, get the maximum "Count", and do +1 in the latest one, but I suspect there must be another way related to properly defining the Count column when creating the table.
The first question is: Why do you need this?
There is ROW_NUMBER() which will - provided the correct PARTITION BY in the OVER() clause - do this for you:
DECLARE #tbl TABLE(ID INT,A VARCHAR(10),B INT);
INSERT INTO #tbl VALUES
(1,'abc',0)
,(2,'abc',0)
,(3,'abc',1)
,(4,'xyz',1)
,(5,'xyz',1)
,(6,'xyz',1)
,(7,'abc',1)
,(8,'abc',0);
SELECT *
,ROW_NUMBER() OVER(PARTITION BY A,B ORDER BY ID)
FROM #tbl
ORDER BY ID;
The problem is: What happens if a row is changed or deleted?
If you write this values into a persistant column and one row is removed physically, you'll have a gap. Okay, one can live with this... But if a value in A is changed from abc to xyz (same applies to B of course) the whole approach breaks.
If you still want to write this into a column you can use the ROW_NUMBER() from above to fill these values initially and a TRIGGER to set the next value with your SELECT MAX()+1 approach for new rows.
If the set of combinations is limited you might create a SEQUENCE (needs v2012+) for each.
But - to be honest - the whole issue smells a bit.
I have a table that has a new column, and updating the values that should go in the new column. For simplicity sake I am reducing my example table structure as well as my query. Below is how i want my output to look.
IDNumber NewColumn
1 1
2 1
3 1
4 2
5 2
WITH CTE_Split
AS
(
select
*,ntile(2) over (order by newid()) as Split
from TableA
)
Update a
set NewColumn = a.Split
from CTE_Split a
Now when I do this I get my table and it looks as such
IDNumber NewColumn
1 1
2 1
3 1
4 1
5 1
However when I do the select only I can see that I get the desire output, now I have done this before to split result sets into multiple groups and everything works within the select but now that I need to update the table I am getting this weird result. Not quiet sure what I'm doing wrong or if anyone can provide any sort of feedback.
So after a whole day of frustration I was able to compare this code and table to another that I had already done this process to. The reason that this table was getting updated to all 1s was because turns out that whoever made the table thought this was supposed to be a bit flag. When it reality it should be an int because in this case its actually only two possible values but in others it could be more than two.
Thank you for all your suggestion and help and it should teach me to scope out data types of tables when using the ntile function.
Try updating your table directly rather than updating your CTE. This makes it clearer what your UPDATE statement does.
Here is an example:
WITH CTE_Split AS
(
SELECT
*,
ntile(2) over (order by newid()) as Split
FROM TableA
)
UPDATE a
SET NewColumn = c.Split
FROM
TableA a
INNER JOIN CTE_Split c ON a.IDNumber = c.IDNumber
I assume that what you want to achieve is to group your records into two randomized partitions. This statement seems to do the job.
I have this table in Sql and in insert Form of my project I prevent the user from entering same HDate for Same HNumber
RecID HDate HNumber HComb
----------------------------------------------
1 2017-1-30 1 12
3 2017-1-29 1 15
5 2017-1-30 2 12
6 2017-1-30 3 12
9 2017-1-30 4 12
But in Edit Form I don't know how to prevent that,
I try this code in stored procedure but it work for some HNumber, But it prevent some other HNumber to be edited in it's own date
Create Procedure UpdCombHarByRecID
#RecID int,
#HarvestDate Date,
#HiveNumber int,
#HoneyComb Float,
as
if NOT Exists (Select * From tHoneyHarvest Where RecID=#RecID)
return 0
//there is no record to be updated
if Exists (Select * From tHoneyHarvest Where HarvestDate=#HarvestDate AND
HiveNumber=HiveNumber And
RecID!=#RecID)
// I hoped this should do the job
//(RecID is PrimaryKey and it is identity)
return 2
Update tHoneyHarvest
Set HarvestDate=#HarvestDate,
HoneyType=#HoneyType,
HoneyComb=#HoneyComb,
HoneyDetails=#HoneyDetails
Where RecID=#RecID
return 1
now where is the problem?
The best way is use non Clustered index .non Clustered index prevent the duplicate records when Inserts or update is going to occur .
CREATE UNIQUE INDEX MyIndex ON ExcelTable(HDate, HNumber)
please refer to
https://supportline.microfocus.com/documentation/books/sx50/rhsqlx1s.htm
Add unique constraint to combination of two columns
thanks for the help in comment. The problem was due to a typo in the procedure.
if Exists (Select * From tHoneyHarvest Where HarvestDate=#HarvestDate AND
HiveNumber=#HiveNumber And
RecID!=#RecID)
I forgot to add # before HiveNumber
I have a table with many rows that is similar to the one below where each EmployeeID is repeated twice. I simply want to sum the TotalAmount column and keep one of the rows based on the content of the Adjustment column. If the content of the Adjustment cell for an employee has a 2 for one row and an 8 for the second record, then keep sum the TotalAmount and keep the row with 2. If they have 8 and 11 then keep 8. If 7 and 8 then keep 8.
The result should look as follows:
You could use:
Select EmployeeID, StartDate, Max(Adjustment), Sum(TotalAmount)
From YourTable
Group By EmployeeID, StartDate
But that will not return 8 for ID 3 and 4. There is no logic telling why 8 should be returned from these IDs.