I have a table in which the history of changes on the product is stored and you want to get a list of records that have changes in Col1 or Col2 or Col3, but do not show me records that have no changes in any of these three columns.
Here is an example made in SQL. How are you doing with Linq?
Create a temporary table for testing
CREATE TABLE #ProductHistorical( IdProductHistorical int IDENTITY(1,1) NOT NULL, IdProduct int NOT NULL, DateChange datetime NULL, Col1 int NOT NULL, Col2 int NOT NULL, Col3 int NOT NULL, CONSTRAINT PK_ProductHistorical PRIMARY KEY CLUSTERED (IdProductHistorical ASC)) GO
Insert test data
INSERT #ProductHistorical ( IdProduct, DateChange, Col1, Col2, Col3) VALUES (1, CAST(0x0000A13900000000 AS DateTime), 1, 2, 3) INSERT #ProductHistorical ( IdProduct, DateChange, Col1, Col2, Col3) VALUES (1, CAST(0x0000A13A00000000 AS DateTime), 1, 2, 3) INSERT #ProductHistorical ( IdProduct, DateChange, Col1, Col2, Col3) VALUES (1, CAST(0x0000A13B00000000 AS DateTime), 1, 2, 3) INSERT #ProductHistorical ( IdProduct, DateChange, Col1, Col2, Col3) VALUES (1, CAST(0x0000A13C00000000 AS DateTime), 1, 1, 3) INSERT #ProductHistorical ( IdProduct, DateChange, Col1, Col2, Col3) VALUES (1, CAST(0x0000A13D00000000 AS DateTime), 1, 1, 3) INSERT #ProductHistorical ( IdProduct, DateChange, Col1, Col2, Col3) VALUES (1, CAST(0x0000A13E00000000 AS DateTime), 2, 2, 2) INSERT #ProductHistorical ( IdProduct, DateChange, Col1, Col2, Col3) VALUES (1, CAST(0x0000A13F00000000 AS DateTime), 2, 2, 2) INSERT #ProductHistorical ( IdProduct, DateChange, Col1, Col2, Col3) VALUES (1, CAST(0x0000A14000000000 AS DateTime), 2, 2, 2) INSERT #ProductHistorical ( IdProduct, DateChange, Col1, Col2, Col3) VALUES (1, CAST(0x0000A14100000000 AS DateTime), 1, 2, 3) INSERT #ProductHistorical ( IdProduct, DateChange, Col1, Col2, Col3) VALUES (2, CAST(0x0000A14200000000 AS DateTime), 1, 1, 1) INSERT #ProductHistorical ( IdProduct, DateChange, Col1, Col2, Col3) VALUES (2, CAST(0x0000A14300000000 AS DateTime), 1, 1, 2)
SQL Query
SELECT phWithChanges.DateChange, phWithChanges.Col1, phWithChanges.Col2, phWithChanges.Col3 FROM #ProductHistorical ph CROSS APPLY ( SELECT TOP 1 * FROM #ProductHistorical phPost WHERE phPost.IdProduct=ph.IdProduct AND phPost.IdProductHistorical>ph.IdProductHistorical AND (phPost.Col1<>ph.Col1 OR phPost.Col2<>ph.Col2 OR phPost.Col2<>ph.Col2) ORDER BY phPost.IdProductHistorical ASC) phWithChanges WHERE ph.IdProduct=1 GROUP BY phWithChanges.DateChange,phWithChanges.Col1,phWithChanges.Col2,phWithChanges.Col3 UNION --Add First Row SELECT * FROM (SELECT TOP 1 phFirst.DateChange, phFirst.Col1, phFirst.Col2, phFirst.Col3 FROM #ProductHistorical phFirst WHERE phFirst.IdProduct=1 ORDER BY phFirst.IdProductHistorical) rowFirst ORDER BY 1
Data
IdProductHistorical IdProduct DateChange Col1 Col2 Col3 ------------------- ----------- ----------------------- ----------- ----------- ----------- 1 1 2013-01-01 00:00:00.000 1 2 3 2 1 2013-01-02 00:00:00.000 1 2 3 3 1 2013-01-03 00:00:00.000 1 2 3 4 1 2013-01-04 00:00:00.000 1 1 3 5 1 2013-01-05 00:00:00.000 1 1 3 6 1 2013-01-06 00:00:00.000 2 2 2 7 1 2013-01-07 00:00:00.000 2 2 2 8 1 2013-01-08 00:00:00.000 2 2 2 9 1 2013-01-09 00:00:00.000 1 2 3 10 2 2013-01-10 00:00:00.000 1 1 1 11 2 2013-01-11 00:00:00.000 1 1 2
Result
DateChange Col1 Col2 Col3 ----------------------- ----------- ----------- ----------- 2013-01-01 00:00:00.000 1 2 3 2013-01-04 00:00:00.000 1 1 3 2013-01-06 00:00:00.000 2 2 2 2013-01-09 00:00:00.000 1 2 3
How are you doing with Linq?
First approach
var query=( from ph in ProductHistorical.Where(p=>p.IdProduct==1) orderby ph.DateChange ascending select new ProductHistoricalItem { DateChange = ph.DataChange, Col1 = ph.Col1, Col2 = ph.Col2, Col3 = ph.Col3 }); List<ProductHistoricalItem> listResult=new List<ProductHistoricalItem>(); ProductHistoricalItem previous = null; foreach (ProductHistoricalItem item in query) { if (previous == null || previous.Col1 != item.Col1 || previous.Col2 != item.Col2 || previous.Col3 != item.Col3) { listResult.Add(item); previous = item; } }
It is not very effective. How can I do this without using a loop?