Group and Select First From Two Tables Linq - entity-framework

I'm trying to create a simple query using EFCore, returning the list of people i'm conversing with, and the last message that was sent between the two of us (pretty much like how it's displayed on Facebook Messenger or Whatsapp). I created the linq query but its generating one hell of an sql query. I'm trying to optimize the linq query to generate a better sql, so here comes the full story:
0. The Two Entities: Visitors and ChatMessages
The Visitor contains the visitor information, and the ChatMessages contains the actual chat.
1. First Try
I tried the first query as follows:
from c in ChatMessages
orderby c.CreatedAt descending
group c by c.VisitorId into x
select x.First()
Which got me the list of latest messages grouped by the visitor id:
which is cool, specially with the short sql query generated:
SELECT [t3].[test], [t3].[Id], [t3].[Message], [t3].[UserId], [t3].[VisitorId], [t3].[isDeleted] AS [IsDeleted], [t3].[CreatedAt], [t3].[CreatedBy], [t3].[LastUpdatedAt], [t3].[LastUpdatedBy], [t3].[isFromVisitor] AS [IsFromVisitor]
FROM (
SELECT [t0].[VisitorId]
FROM [ChatMessages] AS [t0]
GROUP BY [t0].[VisitorId]
) AS [t1]
OUTER APPLY (
SELECT TOP (1) 1 AS [test], [t2].[Id], [t2].[Message], [t2].[UserId], [t2].[VisitorId], [t2].[isDeleted], [t2].[CreatedAt], [t2].[CreatedBy], [t2].[LastUpdatedAt], [t2].[LastUpdatedBy], [t2].[isFromVisitor]
FROM [ChatMessages] AS [t2]
WHERE (([t1].[VisitorId] IS NULL) AND ([t2].[VisitorId] IS NULL)) OR (([t1].[VisitorId] IS NOT NULL) AND ([t2].[VisitorId] IS NOT NULL) AND ([t1].[VisitorId] = [t2].[VisitorId]))
ORDER BY [t2].[CreatedAt] DESC
) AS [t3]
ORDER BY [t3].[CreatedAt] DESC
2. Second Try, Joining the Visitor table as well
Now I want to return the visitor information as well, so I have to join the visitors table:
from c in ChatMessages
join v in Visitors on c.VisitorId equals v.Id
orderby c.CreatedAt descending
group new {Message = c, Visitor = v} by c.Visitor.Id into x
select x
Which generated what I want:
Problem is, the generate SQL query got very messy:
SELECT [t2].[Id] AS [Key]
FROM [ChatMessages] AS [t0]
INNER JOIN [Visitors] AS [t1] ON [t0].[VisitorId] = ([t1].[Id])
LEFT OUTER JOIN [Visitors] AS [t2] ON [t2].[Id] = [t0].[VisitorId]
GROUP BY [t2].[Id]
GO
-- Region Parameters
DECLARE #x1 BigInt = 1
-- EndRegion
SELECT [t0].[Id], [t0].[Message], [t0].[UserId], [t0].[VisitorId], [t0].[isDeleted] AS [IsDeleted], [t0].[CreatedAt], [t0].[CreatedBy], [t0].[LastUpdatedAt], [t0].[LastUpdatedBy], [t0].[isFromVisitor] AS [IsFromVisitor], [t1].[Id] AS [Id2], [t1].[Email], [t1].[Name], [t1].[Phone], [t1].[isDeleted] AS [IsDeleted2], [t1].[CreatedAt] AS [CreatedAt2], [t1].[CreatedBy] AS [CreatedBy2], [t1].[LastUpdatedAt] AS [LastUpdatedAt2], [t1].[LastUpdatedBy] AS [LastUpdatedBy2], [t1].[Fingerprint], [t1].[IP]
FROM [ChatMessages] AS [t0]
INNER JOIN [Visitors] AS [t1] ON [t0].[VisitorId] = ([t1].[Id])
LEFT OUTER JOIN [Visitors] AS [t2] ON [t2].[Id] = [t0].[VisitorId]
WHERE #x1 = [t2].[Id]
ORDER BY [t0].[CreatedAt] DESC
GO
-- Region Parameters
DECLARE #x1 BigInt = 2
-- EndRegion
SELECT [t0].[Id], [t0].[Message], [t0].[UserId], [t0].[VisitorId], [t0].[isDeleted] AS [IsDeleted], [t0].[CreatedAt], [t0].[CreatedBy], [t0].[LastUpdatedAt], [t0].[LastUpdatedBy], [t0].[isFromVisitor] AS [IsFromVisitor], [t1].[Id] AS [Id2], [t1].[Email], [t1].[Name], [t1].[Phone], [t1].[isDeleted] AS [IsDeleted2], [t1].[CreatedAt] AS [CreatedAt2], [t1].[CreatedBy] AS [CreatedBy2], [t1].[LastUpdatedAt] AS [LastUpdatedAt2], [t1].[LastUpdatedBy] AS [LastUpdatedBy2], [t1].[Fingerprint], [t1].[IP]
FROM [ChatMessages] AS [t0]
INNER JOIN [Visitors] AS [t1] ON [t0].[VisitorId] = ([t1].[Id])
LEFT OUTER JOIN [Visitors] AS [t2] ON [t2].[Id] = [t0].[VisitorId]
WHERE #x1 = [t2].[Id]
ORDER BY [t0].[CreatedAt] DESC
GO
-- Region Parameters
DECLARE #x1 BigInt = 3
-- EndRegion
SELECT [t0].[Id], [t0].[Message], [t0].[UserId], [t0].[VisitorId], [t0].[isDeleted] AS [IsDeleted], [t0].[CreatedAt], [t0].[CreatedBy], [t0].[LastUpdatedAt], [t0].[LastUpdatedBy], [t0].[isFromVisitor] AS [IsFromVisitor], [t1].[Id] AS [Id2], [t1].[Email], [t1].[Name], [t1].[Phone], [t1].[isDeleted] AS [IsDeleted2], [t1].[CreatedAt] AS [CreatedAt2], [t1].[CreatedBy] AS [CreatedBy2], [t1].[LastUpdatedAt] AS [LastUpdatedAt2], [t1].[LastUpdatedBy] AS [LastUpdatedBy2], [t1].[Fingerprint], [t1].[IP]
FROM [ChatMessages] AS [t0]
INNER JOIN [Visitors] AS [t1] ON [t0].[VisitorId] = ([t1].[Id])
LEFT OUTER JOIN [Visitors] AS [t2] ON [t2].[Id] = [t0].[VisitorId]
WHERE #x1 = [t2].[Id]
ORDER BY [t0].[CreatedAt] DESC
GO
-- Region Parameters
DECLARE #x1 BigInt = 4
-- EndRegion
SELECT [t0].[Id], [t0].[Message], [t0].[UserId], [t0].[VisitorId], [t0].[isDeleted] AS [IsDeleted], [t0].[CreatedAt], [t0].[CreatedBy], [t0].[LastUpdatedAt], [t0].[LastUpdatedBy], [t0].[isFromVisitor] AS [IsFromVisitor], [t1].[Id] AS [Id2], [t1].[Email], [t1].[Name], [t1].[Phone], [t1].[isDeleted] AS [IsDeleted2], [t1].[CreatedAt] AS [CreatedAt2], [t1].[CreatedBy] AS [CreatedBy2], [t1].[LastUpdatedAt] AS [LastUpdatedAt2], [t1].[LastUpdatedBy] AS [LastUpdatedBy2], [t1].[Fingerprint], [t1].[IP]
FROM [ChatMessages] AS [t0]
INNER JOIN [Visitors] AS [t1] ON [t0].[VisitorId] = ([t1].[Id])
LEFT OUTER JOIN [Visitors] AS [t2] ON [t2].[Id] = [t0].[VisitorId]
WHERE #x1 = [t2].[Id]
ORDER BY [t0].[CreatedAt] DESC
GO
-- Region Parameters
DECLARE #x1 BigInt = 5
-- EndRegion
SELECT [t0].[Id], [t0].[Message], [t0].[UserId], [t0].[VisitorId], [t0].[isDeleted] AS [IsDeleted], [t0].[CreatedAt], [t0].[CreatedBy], [t0].[LastUpdatedAt], [t0].[LastUpdatedBy], [t0].[isFromVisitor] AS [IsFromVisitor], [t1].[Id] AS [Id2], [t1].[Email], [t1].[Name], [t1].[Phone], [t1].[isDeleted] AS [IsDeleted2], [t1].[CreatedAt] AS [CreatedAt2], [t1].[CreatedBy] AS [CreatedBy2], [t1].[LastUpdatedAt] AS [LastUpdatedAt2], [t1].[LastUpdatedBy] AS [LastUpdatedBy2], [t1].[Fingerprint], [t1].[IP]
FROM [ChatMessages] AS [t0]
INNER JOIN [Visitors] AS [t1] ON [t0].[VisitorId] = ([t1].[Id])
LEFT OUTER JOIN [Visitors] AS [t2] ON [t2].[Id] = [t0].[VisitorId]
WHERE #x1 = [t2].[Id]
ORDER BY [t0].[CreatedAt] DESC
GO
-- Region Parameters
DECLARE #x1 BigInt = 6
-- EndRegion
SELECT [t0].[Id], [t0].[Message], [t0].[UserId], [t0].[VisitorId], [t0].[isDeleted] AS [IsDeleted], [t0].[CreatedAt], [t0].[CreatedBy], [t0].[LastUpdatedAt], [t0].[LastUpdatedBy], [t0].[isFromVisitor] AS [IsFromVisitor], [t1].[Id] AS [Id2], [t1].[Email], [t1].[Name], [t1].[Phone], [t1].[isDeleted] AS [IsDeleted2], [t1].[CreatedAt] AS [CreatedAt2], [t1].[CreatedBy] AS [CreatedBy2], [t1].[LastUpdatedAt] AS [LastUpdatedAt2], [t1].[LastUpdatedBy] AS [LastUpdatedBy2], [t1].[Fingerprint], [t1].[IP]
FROM [ChatMessages] AS [t0]
INNER JOIN [Visitors] AS [t1] ON [t0].[VisitorId] = ([t1].[Id])
LEFT OUTER JOIN [Visitors] AS [t2] ON [t2].[Id] = [t0].[VisitorId]
WHERE #x1 = [t2].[Id]
ORDER BY [t0].[CreatedAt] DESC
GO
-- Region Parameters
DECLARE #x1 BigInt = 7
-- EndRegion
SELECT [t0].[Id], [t0].[Message], [t0].[UserId], [t0].[VisitorId], [t0].[isDeleted] AS [IsDeleted], [t0].[CreatedAt], [t0].[CreatedBy], [t0].[LastUpdatedAt], [t0].[LastUpdatedBy], [t0].[isFromVisitor] AS [IsFromVisitor], [t1].[Id] AS [Id2], [t1].[Email], [t1].[Name], [t1].[Phone], [t1].[isDeleted] AS [IsDeleted2], [t1].[CreatedAt] AS [CreatedAt2], [t1].[CreatedBy] AS [CreatedBy2], [t1].[LastUpdatedAt] AS [LastUpdatedAt2], [t1].[LastUpdatedBy] AS [LastUpdatedBy2], [t1].[Fingerprint], [t1].[IP]
FROM [ChatMessages] AS [t0]
INNER JOIN [Visitors] AS [t1] ON [t0].[VisitorId] = ([t1].[Id])
LEFT OUTER JOIN [Visitors] AS [t2] ON [t2].[Id] = [t0].[VisitorId]
WHERE #x1 = [t2].[Id]
ORDER BY [t0].[CreatedAt] DESC
GO
-- Region Parameters
DECLARE #x1 BigInt = 8
-- EndRegion
SELECT [t0].[Id], [t0].[Message], [t0].[UserId], [t0].[VisitorId], [t0].[isDeleted] AS [IsDeleted], [t0].[CreatedAt], [t0].[CreatedBy], [t0].[LastUpdatedAt], [t0].[LastUpdatedBy], [t0].[isFromVisitor] AS [IsFromVisitor], [t1].[Id] AS [Id2], [t1].[Email], [t1].[Name], [t1].[Phone], [t1].[isDeleted] AS [IsDeleted2], [t1].[CreatedAt] AS [CreatedAt2], [t1].[CreatedBy] AS [CreatedBy2], [t1].[LastUpdatedAt] AS [LastUpdatedAt2], [t1].[LastUpdatedBy] AS [LastUpdatedBy2], [t1].[Fingerprint], [t1].[IP]
FROM [ChatMessages] AS [t0]
INNER JOIN [Visitors] AS [t1] ON [t0].[VisitorId] = ([t1].[Id])
LEFT OUTER JOIN [Visitors] AS [t2] ON [t2].[Id] = [t0].[VisitorId]
WHERE #x1 = [t2].[Id]
ORDER BY [t0].[CreatedAt] DESC
GO
-- Region Parameters
DECLARE #x1 BigInt = 9
-- EndRegion
SELECT [t0].[Id], [t0].[Message], [t0].[UserId], [t0].[VisitorId], [t0].[isDeleted] AS [IsDeleted], [t0].[CreatedAt], [t0].[CreatedBy], [t0].[LastUpdatedAt], [t0].[LastUpdatedBy], [t0].[isFromVisitor] AS [IsFromVisitor], [t1].[Id] AS [Id2], [t1].[Email], [t1].[Name], [t1].[Phone], [t1].[isDeleted] AS [IsDeleted2], [t1].[CreatedAt] AS [CreatedAt2], [t1].[CreatedBy] AS [CreatedBy2], [t1].[LastUpdatedAt] AS [LastUpdatedAt2], [t1].[LastUpdatedBy] AS [LastUpdatedBy2], [t1].[Fingerprint], [t1].[IP]
FROM [ChatMessages] AS [t0]
INNER JOIN [Visitors] AS [t1] ON [t0].[VisitorId] = ([t1].[Id])
LEFT OUTER JOIN [Visitors] AS [t2] ON [t2].[Id] = [t0].[VisitorId]
WHERE #x1 = [t2].[Id]
ORDER BY [t0].[CreatedAt] DESC
GO
-- Region Parameters
DECLARE #x1 BigInt = 10
-- EndRegion
SELECT [t0].[Id], [t0].[Message], [t0].[UserId], [t0].[VisitorId], [t0].[isDeleted] AS [IsDeleted], [t0].[CreatedAt], [t0].[CreatedBy], [t0].[LastUpdatedAt], [t0].[LastUpdatedBy], [t0].[isFromVisitor] AS [IsFromVisitor], [t1].[Id] AS [Id2], [t1].[Email], [t1].[Name], [t1].[Phone], [t1].[isDeleted] AS [IsDeleted2], [t1].[CreatedAt] AS [CreatedAt2], [t1].[CreatedBy] AS [CreatedBy2], [t1].[LastUpdatedAt] AS [LastUpdatedAt2], [t1].[LastUpdatedBy] AS [LastUpdatedBy2], [t1].[Fingerprint], [t1].[IP]
FROM [ChatMessages] AS [t0]
INNER JOIN [Visitors] AS [t1] ON [t0].[VisitorId] = ([t1].[Id])
LEFT OUTER JOIN [Visitors] AS [t2] ON [t2].[Id] = [t0].[VisitorId]
WHERE #x1 = [t2].[Id]
ORDER BY [t0].[CreatedAt] DESC
GO
-- Region Parameters
DECLARE #x1 BigInt = 11
-- EndRegion
SELECT [t0].[Id], [t0].[Message], [t0].[UserId], [t0].[VisitorId], [t0].[isDeleted] AS [IsDeleted], [t0].[CreatedAt], [t0].[CreatedBy], [t0].[LastUpdatedAt], [t0].[LastUpdatedBy], [t0].[isFromVisitor] AS [IsFromVisitor], [t1].[Id] AS [Id2], [t1].[Email], [t1].[Name], [t1].[Phone], [t1].[isDeleted] AS [IsDeleted2], [t1].[CreatedAt] AS [CreatedAt2], [t1].[CreatedBy] AS [CreatedBy2], [t1].[LastUpdatedAt] AS [LastUpdatedAt2], [t1].[LastUpdatedBy] AS [LastUpdatedBy2], [t1].[Fingerprint], [t1].[IP]
FROM [ChatMessages] AS [t0]
INNER JOIN [Visitors] AS [t1] ON [t0].[VisitorId] = ([t1].[Id])
LEFT OUTER JOIN [Visitors] AS [t2] ON [t2].[Id] = [t0].[VisitorId]
WHERE #x1 = [t2].[Id]
ORDER BY [t0].[CreatedAt] DESC
GO
-- Region Parameters
DECLARE #x1 BigInt = 12
-- EndRegion
SELECT [t0].[Id], [t0].[Message], [t0].[UserId], [t0].[VisitorId], [t0].[isDeleted] AS [IsDeleted], [t0].[CreatedAt], [t0].[CreatedBy], [t0].[LastUpdatedAt], [t0].[LastUpdatedBy], [t0].[isFromVisitor] AS [IsFromVisitor], [t1].[Id] AS [Id2], [t1].[Email], [t1].[Name], [t1].[Phone], [t1].[isDeleted] AS [IsDeleted2], [t1].[CreatedAt] AS [CreatedAt2], [t1].[CreatedBy] AS [CreatedBy2], [t1].[LastUpdatedAt] AS [LastUpdatedAt2], [t1].[LastUpdatedBy] AS [LastUpdatedBy2], [t1].[Fingerprint], [t1].[IP]
FROM [ChatMessages] AS [t0]
INNER JOIN [Visitors] AS [t1] ON [t0].[VisitorId] = ([t1].[Id])
LEFT OUTER JOIN [Visitors] AS [t2] ON [t2].[Id] = [t0].[VisitorId]
WHERE #x1 = [t2].[Id]
ORDER BY [t0].[CreatedAt] DESC
GO
-- Region Parameters
DECLARE #x1 BigInt = 13
-- EndRegion
SELECT [t0].[Id], [t0].[Message], [t0].[UserId], [t0].[VisitorId], [t0].[isDeleted] AS [IsDeleted], [t0].[CreatedAt], [t0].[CreatedBy], [t0].[LastUpdatedAt], [t0].[LastUpdatedBy], [t0].[isFromVisitor] AS [IsFromVisitor], [t1].[Id] AS [Id2], [t1].[Email], [t1].[Name], [t1].[Phone], [t1].[isDeleted] AS [IsDeleted2], [t1].[CreatedAt] AS [CreatedAt2], [t1].[CreatedBy] AS [CreatedBy2], [t1].[LastUpdatedAt] AS [LastUpdatedAt2], [t1].[LastUpdatedBy] AS [LastUpdatedBy2], [t1].[Fingerprint], [t1].[IP]
FROM [ChatMessages] AS [t0]
INNER JOIN [Visitors] AS [t1] ON [t0].[VisitorId] = ([t1].[Id])
LEFT OUTER JOIN [Visitors] AS [t2] ON [t2].[Id] = [t0].[VisitorId]
WHERE #x1 = [t2].[Id]
ORDER BY [t0].[CreatedAt] DESC
GO
-- Region Parameters
DECLARE #x1 BigInt = 14
-- EndRegion
SELECT [t0].[Id], [t0].[Message], [t0].[UserId], [t0].[VisitorId], [t0].[isDeleted] AS [IsDeleted], [t0].[CreatedAt], [t0].[CreatedBy], [t0].[LastUpdatedAt], [t0].[LastUpdatedBy], [t0].[isFromVisitor] AS [IsFromVisitor], [t1].[Id] AS [Id2], [t1].[Email], [t1].[Name], [t1].[Phone], [t1].[isDeleted] AS [IsDeleted2], [t1].[CreatedAt] AS [CreatedAt2], [t1].[CreatedBy] AS [CreatedBy2], [t1].[LastUpdatedAt] AS [LastUpdatedAt2], [t1].[LastUpdatedBy] AS [LastUpdatedBy2], [t1].[Fingerprint], [t1].[IP]
FROM [ChatMessages] AS [t0]
INNER JOIN [Visitors] AS [t1] ON [t0].[VisitorId] = ([t1].[Id])
LEFT OUTER JOIN [Visitors] AS [t2] ON [t2].[Id] = [t0].[VisitorId]
WHERE #x1 = [t2].[Id]
ORDER BY [t0].[CreatedAt] DESC
GO
-- Region Parameters
DECLARE #x1 BigInt = 15
-- EndRegion
SELECT [t0].[Id], [t0].[Message], [t0].[UserId], [t0].[VisitorId], [t0].[isDeleted] AS [IsDeleted], [t0].[CreatedAt], [t0].[CreatedBy], [t0].[LastUpdatedAt], [t0].[LastUpdatedBy], [t0].[isFromVisitor] AS [IsFromVisitor], [t1].[Id] AS [Id2], [t1].[Email], [t1].[Name], [t1].[Phone], [t1].[isDeleted] AS [IsDeleted2], [t1].[CreatedAt] AS [CreatedAt2], [t1].[CreatedBy] AS [CreatedBy2], [t1].[LastUpdatedAt] AS [LastUpdatedAt2], [t1].[LastUpdatedBy] AS [LastUpdatedBy2], [t1].[Fingerprint], [t1].[IP]
FROM [ChatMessages] AS [t0]
INNER JOIN [Visitors] AS [t1] ON [t0].[VisitorId] = ([t1].[Id])
LEFT OUTER JOIN [Visitors] AS [t2] ON [t2].[Id] = [t0].[VisitorId]
WHERE #x1 = [t2].[Id]
ORDER BY [t0].[CreatedAt] DESC
GO
-- Region Parameters
DECLARE #x1 BigInt = 16
-- EndRegion
SELECT [t0].[Id], [t0].[Message], [t0].[UserId], [t0].[VisitorId], [t0].[isDeleted] AS [IsDeleted], [t0].[CreatedAt], [t0].[CreatedBy], [t0].[LastUpdatedAt], [t0].[LastUpdatedBy], [t0].[isFromVisitor] AS [IsFromVisitor], [t1].[Id] AS [Id2], [t1].[Email], [t1].[Name], [t1].[Phone], [t1].[isDeleted] AS [IsDeleted2], [t1].[CreatedAt] AS [CreatedAt2], [t1].[CreatedBy] AS [CreatedBy2], [t1].[LastUpdatedAt] AS [LastUpdatedAt2], [t1].[LastUpdatedBy] AS [LastUpdatedBy2], [t1].[Fingerprint], [t1].[IP]
FROM [ChatMessages] AS [t0]
INNER JOIN [Visitors] AS [t1] ON [t0].[VisitorId] = ([t1].[Id])
LEFT OUTER JOIN [Visitors] AS [t2] ON [t2].[Id] = [t0].[VisitorId]
WHERE #x1 = [t2].[Id]
ORDER BY [t0].[CreatedAt] DESC
GO
-- Region Parameters
DECLARE #x1 BigInt = 17
-- EndRegion
SELECT [t0].[Id], [t0].[Message], [t0].[UserId], [t0].[VisitorId], [t0].[isDeleted] AS [IsDeleted], [t0].[CreatedAt], [t0].[CreatedBy], [t0].[LastUpdatedAt], [t0].[LastUpdatedBy], [t0].[isFromVisitor] AS [IsFromVisitor], [t1].[Id] AS [Id2], [t1].[Email], [t1].[Name], [t1].[Phone], [t1].[isDeleted] AS [IsDeleted2], [t1].[CreatedAt] AS [CreatedAt2], [t1].[CreatedBy] AS [CreatedBy2], [t1].[LastUpdatedAt] AS [LastUpdatedAt2], [t1].[LastUpdatedBy] AS [LastUpdatedBy2], [t1].[Fingerprint], [t1].[IP]
FROM [ChatMessages] AS [t0]
INNER JOIN [Visitors] AS [t1] ON [t0].[VisitorId] = ([t1].[Id])
LEFT OUTER JOIN [Visitors] AS [t2] ON [t2].[Id] = [t0].[VisitorId]
WHERE #x1 = [t2].[Id]
ORDER BY [t0].[CreatedAt] DESC
GO
-- Region Parameters
DECLARE #x1 BigInt = 18
-- EndRegion
SELECT [t0].[Id], [t0].[Message], [t0].[UserId], [t0].[VisitorId], [t0].[isDeleted] AS [IsDeleted], [t0].[CreatedAt], [t0].[CreatedBy], [t0].[LastUpdatedAt], [t0].[LastUpdatedBy], [t0].[isFromVisitor] AS [IsFromVisitor], [t1].[Id] AS [Id2], [t1].[Email], [t1].[Name], [t1].[Phone], [t1].[isDeleted] AS [IsDeleted2], [t1].[CreatedAt] AS [CreatedAt2], [t1].[CreatedBy] AS [CreatedBy2], [t1].[LastUpdatedAt] AS [LastUpdatedAt2], [t1].[LastUpdatedBy] AS [LastUpdatedBy2], [t1].[Fingerprint], [t1].[IP]
FROM [ChatMessages] AS [t0]
INNER JOIN [Visitors] AS [t1] ON [t0].[VisitorId] = ([t1].[Id])
LEFT OUTER JOIN [Visitors] AS [t2] ON [t2].[Id] = [t0].[VisitorId]
WHERE #x1 = [t2].[Id]
ORDER BY [t0].[CreatedAt] DESC
GO
-- Region Parameters
DECLARE #x1 BigInt = 19
-- EndRegion
SELECT [t0].[Id], [t0].[Message], [t0].[UserId], [t0].[VisitorId], [t0].[isDeleted] AS [IsDeleted], [t0].[CreatedAt], [t0].[CreatedBy], [t0].[LastUpdatedAt], [t0].[LastUpdatedBy], [t0].[isFromVisitor] AS [IsFromVisitor], [t1].[Id] AS [Id2], [t1].[Email], [t1].[Name], [t1].[Phone], [t1].[isDeleted] AS [IsDeleted2], [t1].[CreatedAt] AS [CreatedAt2], [t1].[CreatedBy] AS [CreatedBy2], [t1].[LastUpdatedAt] AS [LastUpdatedAt2], [t1].[LastUpdatedBy] AS [LastUpdatedBy2], [t1].[Fingerprint], [t1].[IP]
FROM [ChatMessages] AS [t0]
INNER JOIN [Visitors] AS [t1] ON [t0].[VisitorId] = ([t1].[Id])
LEFT OUTER JOIN [Visitors] AS [t2] ON [t2].[Id] = [t0].[VisitorId]
WHERE #x1 = [t2].[Id]
ORDER BY [t0].[CreatedAt] DESC
GO
-- Region Parameters
DECLARE #x1 BigInt = 20
-- EndRegion
SELECT [t0].[Id], [t0].[Message], [t0].[UserId], [t0].[VisitorId], [t0].[isDeleted] AS [IsDeleted], [t0].[CreatedAt], [t0].[CreatedBy], [t0].[LastUpdatedAt], [t0].[LastUpdatedBy], [t0].[isFromVisitor] AS [IsFromVisitor], [t1].[Id] AS [Id2], [t1].[Email], [t1].[Name], [t1].[Phone], [t1].[isDeleted] AS [IsDeleted2], [t1].[CreatedAt] AS [CreatedAt2], [t1].[CreatedBy] AS [CreatedBy2], [t1].[LastUpdatedAt] AS [LastUpdatedAt2], [t1].[LastUpdatedBy] AS [LastUpdatedBy2], [t1].[Fingerprint], [t1].[IP]
FROM [ChatMessages] AS [t0]
INNER JOIN [Visitors] AS [t1] ON [t0].[VisitorId] = ([t1].[Id])
LEFT OUTER JOIN [Visitors] AS [t2] ON [t2].[Id] = [t0].[VisitorId]
WHERE #x1 = [t2].[Id]
ORDER BY [t0].[CreatedAt] DESC
Which does not seem like a query i would want to fire at the database. Moreover, when executing this code inside the asp.net core app, im getting an exception EF.Property called with wrong property name., not sure why:
crit: converse_app.Controllers.VisitorsController[0]
There was an error on 'GetVisitorsAsync' invocation: System.InvalidOperationException: EF.Property called with wrong property name.
at Microsoft.EntityFrameworkCore.Query.RelationalSqlTranslatingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression)
at Microsoft.EntityFrameworkCore.Query.RelationalSqlTranslatingExpressionVisitor.VisitBinary(BinaryExpression binaryExpression)
at Microsoft.EntityFrameworkCore.SqlServer.Query.Internal.SqlServerSqlTranslatingExpressionVisitor.VisitBinary(BinaryExpression binaryExpression)
at Microsoft.EntityFrameworkCore.Query.RelationalSqlTranslatingExpressionVisitor.Translate(Expression expression)
at Microsoft.EntityFrameworkCore.Query.RelationalQueryableMethodTranslatingExpressionVisitor.WeakEntityExpandingExpressionVisitor.Expand(Expression source, MemberIdentity member)
at Microsoft.EntityFrameworkCore.Query.RelationalQueryableMethodTranslatingExpressionVisitor.WeakEntityExpandingExpressionVisitor.VisitMember(MemberExpression memberExpression)
at Microsoft.EntityFrameworkCore.Query.RelationalQueryableMethodTranslatingExpressionVisitor.WeakEntityExpandingExpressionVisitor.VisitMember(MemberExpression memberExpression)
at Microsoft.EntityFrameworkCore.Query.RelationalQueryableMethodTranslatingExpressionVisitor.WeakEntityExpandingExpressionVisitor.Expand(SelectExpression selectExpression, Expression lambdaBody)
at Microsoft.EntityFrameworkCore.Query.RelationalQueryableMethodTranslatingExpressionVisitor.RemapLambdaBody(ShapedQueryExpression shapedQueryExpression, LambdaExpression lambdaExpression)
at Microsoft.EntityFrameworkCore.Query.RelationalQueryableMethodTranslatingExpressionVisitor.TranslateGroupBy(ShapedQueryExpression source, LambdaExpression keySelector, LambdaExpression elementSelector, LambdaExpression resultSelector)
at Microsoft.EntityFrameworkCore.Query.QueryableMethodTranslatingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression)
at Microsoft.EntityFrameworkCore.Query.RelationalQueryableMethodTranslatingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression)
at Microsoft.EntityFrameworkCore.Query.QueryableMethodTranslatingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression)
at Microsoft.EntityFrameworkCore.Query.RelationalQueryableMethodTranslatingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression)
at Microsoft.EntityFrameworkCore.Query.QueryCompilationContext.CreateQueryExecutor[TResult](Expression query)
at Microsoft.EntityFrameworkCore.Storage.Database.CompileQuery[TResult](Expression query, Boolean async)
at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.CompileQueryCore[TResult](IDatabase database, Expression query, IModel model, Boolean async)
at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.<>c__DisplayClass9_0`1.<Execute>b__0()
at Microsoft.EntityFrameworkCore.Query.Internal.CompiledQueryCache.GetOrAddQueryCore[TFunc](Object cacheKey, Func`1 compiler)
at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.Execute[TResult](Expression query)
at Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryProvider.Execute[TResult](Expression expression)
at Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryable`1.GetEnumerator()
at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
at converse_app.Controllers.VisitorsController.GetVisitorsAsync(Int32 pageSize, Int32 pageNumber
Sorry for the long for the post, so my question is how can i optimize the linq query for a better sql output, as well as the reason this error might be firing.
I'm using .NET Core 3 preview8 with EF Core 3 preview8, and running against MSSQL.

The query you are looking for standardly is expressed in LINQ to Entities (EF) with something like this (no joins, no GroupBy, use navigation properties):
var query = context.Visitors
.Select(v => new
{
Visitor = v,
Message = v.VisitorChatMessages
.OrderByDescending(m => m.CreatedAt)
.FirstOrDefault()
});
But here is the trap. EF6 creates quite inefficient SQL query, and EF Core until now produces (again quite inefficient) N + 1 SQL queries.
But this is changing in EF Core 3.0 in a positive direction! Usually (and still) I don't recommend using the preview (beta) versions of EF Core 3.0, because they are rewriting the whole query translation/processing pipeline, so many things don't work as expected.
But today I've updated my EF Core test environment to EF Core 3.0 Preview 9 and I'm pleased to see that the above query now nicely translates to the following single SQL query:
SELECT [v].[Id], [v].[CreatedAt], [v].[CreatedBy], [v].[Email], [v].[Fingerprint], [v].[IP], [v].[IsDeleted], [v].[LastUpdatedAt], [v].[LastUpdatedBy], [v].[Name], [v].[Phone], [t0].[Id], [t0].[CreatedAt], [t0].[CreatedBy], [t0].[IsDeleted], [t0].[IsFromVisitor], [t0].[LastUpdatedAt], [t0].[LastUpdatedBy], [t0].[Message], [t0].[UserId], [t0].[VisitorId]
FROM [Visitors] AS [v]
LEFT JOIN (
SELECT [t].[Id], [t].[CreatedAt], [t].[CreatedBy], [t].[IsDeleted], [t].[IsFromVisitor], [t].[LastUpdatedAt], [t].[LastUpdatedBy], [t].[Message], [t].[UserId], [t].[VisitorId]
FROM (
SELECT [c].[Id], [c].[CreatedAt], [c].[CreatedBy], [c].[IsDeleted], [c].[IsFromVisitor], [c].[LastUpdatedAt], [c].[LastUpdatedBy], [c].[Message], [c].[UserId], [c].[VisitorId], ROW_NUMBER() OVER(PARTITION BY [c].[VisitorId] ORDER BY [c].[CreatedAt] DESC) AS [row]
FROM [ChatMessages] AS [c]
) AS [t]
WHERE [t].[row] <= 1
) AS [t0] ON [v].[Id] = [t0].[VisitorId]
Note the beautiful utilization of the ROW_NUMBER() OVER (PARTITION BY ORDER BY) construct. This is the first time EF query translation does that ever. I'm excited. Good job, EF Core team!
Update: The exact equivalent of your first query (which btw fails with runtime exception in Preview 9)
from c in context.ChatMessages
orderby c.CreatedAt descending
group c by c.VisitorId into x
select x.First()
but with additional information is
from v in context.Visitors
from c in v.VisitorChatMessages
.OrderByDescending(c => c.CreatedAt)
.Take(1)
orderby c.CreatedAt descending
select new
{
Visitor = v,
Message = c
})
The generated SQL is pretty much the same - just the LEFT OUTER JOIN becomes INNER JOIN and there is additional ORDER BY at the end.
Looks like that to make this work, it's essential to avoid GroupBy and use GroupJoin (which collection navigation property represents in LINQ to Entities queries) or correlated SelectMany to achieve the desired grouping.

You should be able to get your visitor information via association without explicitly trying to join/group on it.
Apologies for switching to Fluent syntax, I really dislike the Linq QL, it always seems so forced to do anything through it... :)
Your original query:
from c in ChatMessages
orderby c.CreatedAt descending
group c by c.VisitorId into x
select x.First()
or
var groupedMessages = context.ChatMessages
.OrderByDescending(c => c.CreatedAt)
.GroupBy(c => c.VisitorId)
.First();
To group by Visitor:
var groupedMessages = context.ChatMessages
.OrderByDescending(c => c.CreatedAt)
.GroupBy(c => c.Visitor)
.First();
This will give you a Key as a Visitor entity, with the messages for that visitor.
However, this somewhat begs the question, why?
var visitorsWithMessages = context.Visitors.Include(v => v.VisitorChatMessages);
This loads the visitors and eager-loads their associated chat messages. Entities satisfy queries against the data relationships. For consumption though we care about details like ensuring the chat messages are ordered, or possibly filtered.
To project that into a suitable structure I'd use view models for the visitor and chat message to optimize the query to cover just the details I care about, and present them in the way I care about:
var visitorsWithMessages = context.Visitors
// insert .Where() clause here to filter which Visitors we care to retrieve...
.Select(v => new VisitorViewModel
{
Id = v.Id,
Name = v.Name,
RecentChatMessages = v.VisitorChatMessages
.OrderByDescending(c => c.CreatedAt)
.Select(c => new ChatMessageViewModel
{
Id = c.Id,
Message = c.Message,
CreatedAt = c.CreatedAt,
CreatedBy = c.User.UserName ?? "Anonymous"
}).Take(10).ToList()
}).ToList();
This uses projection and EF's mapped relationships to get a list of Visitors and up to 10 of their most recent chat messages. I populate simple POCO view model classes which contain the fields I care about. These view models can be safely returned from methods or serialized to a view/API consumer without risking tripping up lazy loading. If I just need the data and don't need to send it anywhere, I can use anonymous types to get the fields I care about. We don't need to explicitly join entities together, you only need to do that for entities that deliberately do not have FK relationships mapped. We also do not need to deliberately eager-load entities either. The Select will compose an optimized SQL statement for the columns we need.
You can consume those results in the view and render based on Visitor + Messages or even dive deeper if you want to display a list of each visitors 10 most recent messages /w visitor details as a flattened list of messages:
Edit: The below query may have had an issue by accessing "v." after the .SelectMany. Corrected to "c.Visitor."
var recentMessages = context.Visitors
.SelectMany(v => v.VisitorChatMessages
.OrderByDescending(c => c.CreatedAt)
.Select(c => new VisitorChatMessageViewModel
{
Id = c.Id,
VisitorId = c.Visitor.Id,
Message = c.Message,
CreatedAt = c.CreatedAt,
CreatedBy = c.User.UserName ?? "Anonymous",
Visitor = c.Visitor.Name
}).Take(10)
}).ToList();
No idea how to do that in Linq QL though. :)
Edit: That last example will give you the last 10 messages with their applicable Visitor detail. (Name)
To get the last 100 messages for example and group them by their visitor:
var recentMessages = context.Visitors
.SelectMany(v => v.VisitorChatMessages
.OrderByDescending(c => c.CreatedAt)
.Select(c => new VisitorChatMessageViewModel
{
Id = c.Id,
VisitorId = c.Visitor.Id,
Message = c.Message,
CreatedAt = c.CreatedAt,
CreatedBy = c.User.UserName ?? "Anonymous",
Visitor = c.Visitor.Name // Visitor Name, or could be a ViewModel for more info about Visitor...
}).Take(100)
}).GroupBy(x => x.Visitor).ToList();
If you select a VisitorViewModel for Visitor instead of ".Visitor.Name" then your grouping key will have access to Name, Id, etc. whatever you select from the associated Visitor.

Related

How to list all constraints of a table in PostgreSQL?

How to list all constraints (Primary key, Foreign Key, check, unique mutual exclusive, ..) of a table in PostgreSQL?
Constraints of the table can be retrieved from catalog-pg-constraint. using the SELECT query.
SELECT con.*
FROM pg_catalog.pg_constraint con
INNER JOIN pg_catalog.pg_class rel ON rel.oid = con.conrelid
INNER JOIN pg_catalog.pg_namespace nsp ON nsp.oid = connamespace
WHERE nsp.nspname = '{schema name}'
AND rel.relname = '{table name}';
and the same can be viewed in PSQL using
\d+ {SCHEMA_NAME.TABLE_NAME}
Here is POSTGRES specific answer
..... it will retrive all columns and their relationship as well
SELECT * FROM (
SELECT
pgc.contype as constraint_type,
pgc.conname as constraint_name,
ccu.table_schema AS table_schema,
kcu.table_name as table_name,
CASE WHEN (pgc.contype = 'f') THEN kcu.COLUMN_NAME ELSE ccu.COLUMN_NAME END as column_name,
CASE WHEN (pgc.contype = 'f') THEN ccu.TABLE_NAME ELSE (null) END as reference_table,
CASE WHEN (pgc.contype = 'f') THEN ccu.COLUMN_NAME ELSE (null) END as reference_col,
CASE WHEN (pgc.contype = 'p') THEN 'yes' ELSE 'no' END as auto_inc,
CASE WHEN (pgc.contype = 'p') THEN 'NO' ELSE 'YES' END as is_nullable,
'integer' as data_type,
'0' as numeric_scale,
'32' as numeric_precision
FROM
pg_constraint AS pgc
JOIN pg_namespace nsp ON nsp.oid = pgc.connamespace
JOIN pg_class cls ON pgc.conrelid = cls.oid
JOIN information_schema.key_column_usage kcu ON kcu.constraint_name = pgc.conname
LEFT JOIN information_schema.constraint_column_usage ccu ON pgc.conname = ccu.CONSTRAINT_NAME
AND nsp.nspname = ccu.CONSTRAINT_SCHEMA
UNION
SELECT null as constraint_type , null as constraint_name , 'public' as "table_schema" ,
table_name , column_name, null as refrence_table , null as refrence_col , 'no' as auto_inc ,
is_nullable , data_type, numeric_scale , numeric_precision
FROM information_schema.columns cols
Where 1=1
AND table_schema = 'public'
and column_name not in(
SELECT CASE WHEN (pgc.contype = 'f') THEN kcu.COLUMN_NAME ELSE kcu.COLUMN_NAME END
FROM
pg_constraint AS pgc
JOIN pg_namespace nsp ON nsp.oid = pgc.connamespace
JOIN pg_class cls ON pgc.conrelid = cls.oid
JOIN information_schema.key_column_usage kcu ON kcu.constraint_name = pgc.conname
LEFT JOIN information_schema.constraint_column_usage ccu ON pgc.conname = ccu.CONSTRAINT_NAME
AND nsp.nspname = ccu.CONSTRAINT_SCHEMA
)
) as foo
ORDER BY table_name desc
I wasn't able to get the above solutions to work. Maybe they're no longer supported or more likely I'm doing something wrong. This is how I got it to work. Note that the "contype" column will be abbreviated with the constraint type (e.g. 'c' for check, 'p' for primary key, etc.). I include that variable in case you want to add a WHERE statement to filter for it after the FROM block.
select pgc.conname as constraint_name,
ccu.table_schema as table_schema,
ccu.table_name,
ccu.column_name,
contype,
pg_get_constraintdef(pgc.oid)
from pg_constraint pgc
join pg_namespace nsp on nsp.oid = pgc.connamespace
join pg_class cls on pgc.conrelid = cls.oid
left join information_schema.constraint_column_usage ccu
on pgc.conname = ccu.constraint_name
and nsp.nspname = ccu.constraint_schema
order by pgc.conname;
SELECT constraint_name, table_name, column_name, ordinal_position FROM information_schema.key_column_usage WHERE table_name = 'put your table name here';

display constraints of Certain table in Postgresql

I want to know how to display all constraints of a certain table(all columns) by the SELECT statement in PostgreSQL. I tried this code:
SELECT * FROM information_schema.table_constraints;
SELECT * FROM information_schema.referential_constraints;
Actually, I want the primary keys and foreign keys of the tables
Following should do the trick. Just change table-name-goes-here with your table name.
SELECT
tc.table_schema, tc.constraint_name, tc.table_name, kcu.column_name,
ccu.table_schema AS foreign_table_schema,
ccu.table_name AS foreign_table_name,
ccu.column_name AS foreign_column_name
FROM
information_schema.table_constraints AS tc
JOIN information_schema.key_column_usage AS kcu
ON tc.constraint_name = kcu.constraint_name
JOIN information_schema.constraint_column_usage AS ccu
ON ccu.constraint_name = tc.constraint_name
WHERE constraint_type in ('PRIMARY KEY', 'FOREIGN KEY')
AND tc.table_name='table-name-goes-here';

PG_Depend Column Alias (view) to Source Column (table) mapping dependancy

I'm using version 8.2 Postresql
Have been trying to do this for days now, and I keep hitting the same wall. How to Display the following:
Source Table || Source_column || Target View || Target Column
Stg_table1|| customerid || vw_customer || Customer_details_id
The biggest problem I have is that I can't link the Alias names in the view, back to the Source_column. This is because the Ordinal position of the columns in the Source_table, is different to the columns in the Target_view.
I have tried using these scripts, with no luck (this joins the columns back on using information schema, and Ordinal Position)
select distinct
a.attname AS SOURCE
, a.attname::information_schema.sql_identifier AS column_name
--, format_type(a.atttypid, NULL) AS Source_Type
, d.refobjid::regclass AS Source_table
, r.ev_class::regclass AS Target_View
--, pt.Typname AS TYPE, a.*
--, c.Column_name AS Target
--, c.Data_type
from pg_attribute as a
join pg_depend as d on d.refobjid = a.attrelid and d.refobjsubid = a.attnum
join pg_rewrite as r on d.objid = r.oid
--join information_schema.columns c ON a.attnum = c.ordinal_position --and r.ev_class::regclass = c.table_schema||'.'||c.table_name
--join pg_type as pt on a.atttypid = pt.oid
JOIN pg_class
ON pg_class.oid = a.attrelid
AND a.attnum > 0
where
r.ev_class = 'abc.vw_customer'::regclass
and c.table_schema||'.'||c.table_name = 'vw_customer';
And I have also tried it this way:
SELECT distinct dependent.relname, pg_attribute.attname
, pg_attrdef.*
--, pg_attribute.attname::information_schema.sql_identifier AS column_name
--, pg_depend.objid, pg_attribute.*
FROM pg_depend
JOIN pg_rewrite ON pg_depend.objid = pg_rewrite.oid
JOIN pg_class as dependee ON pg_rewrite.ev_class = dependee.oid
JOIN pg_class as dependent ON pg_depend.refobjid = dependent.oid
JOIN pg_attribute ON pg_depend.refobjid = pg_attribute.attrelid
--AND pg_depend.refobjsubid = pg_attribute.attnum
LEFT JOIN pg_attrdef ON pg_attribute.attrelid = pg_attrdef.adrelid AND pg_attribute.attnum = pg_attrdef.adnum
WHERE dependee.relname = 'vw_customer'
--and attname in ('Customer_details_id', 'customerid')
AND pg_attribute.attnum > 0

Decryption Error in Query

I have a large query that encrypts/decrypts one table in PostgreSQL. I added a new conditional to this query and it now throws an error. The original query retrieves all records based on date and inner join relevance (all records from tblSessions that meet the conditions).
The updated query retrieves only records from tblSessions where parent_session_id is not null (any records from tblSessions that have a child record are omitted from results).
tblsessions (only showing fields that pertain to join conditions)
sessionid | decision_id | start_time | end_time | is_comlete | parent_session_id
---------------------------------------------------------------------------------
SERIAL | BYTEA | BYTEA | BYTEA | BYTEA | INTEGER DEFAULT 0
In the SQL window of Posgres, Running the second query gives me the following error:
ERROR: function decrypt(integer, "unknown", "unknown") does not exist
SQL state: 42883
Hint: No function matches the given name and argument types. You may need to add explicit type casts.
Original query (works):
SELECT z.conditionname, x.name AS domainname, d.decisionName,
c.firstname AS counselor_first_name, c.lastname AS counselor_last_name,
o.name AS organization_name,
encode(decrypt(s.start_time, '####salt####', '###encryption mode###'), 'escape') AS start_time,
encode(decrypt(s.end_time, '####salt####', '###encryption mode###'), 'escape') AS end_time,
encode(decrypt(s.is_complete, '####salt####', '###encryption mode###'), 'escape') AS is_complete,
s.parent_session_id
FROM tblDecisions d
INNER JOIN tblSessions s ON encode(decrypt(s.decision_id, '####salt####', '###encryption mode###'), 'escape') = d.decisionid
INNER JOIN tblCounselors c ON encode(decrypt(s.counselor_ck, '####salt####', '###encryption mode###'), 'escape') = c.campuskey
INNER JOIN tblCounselor_to_organization co ON co.counselor_id = c.counselorid
INNER JOIN tblOrganizations o ON o.organizationid = co.organization_id
INNER JOIN tblDomains x ON x.domainid = d.domain_id
INNER JOIN tblConditions z ON z.conditionid = x.condition_id
AND encode(decrypt(s.start_time, '####salt####', '###encryption mode###'), 'escape') >= '2012-01-01 00:00:00'
AND encode(decrypt(s.is_complete, '####salt####', '###encryption mode###'), 'escape') = 'true'
ORDER BY encode(decrypt(s.start_time, '####salt####', '###encryption mode###'), 'escape'), encode(decrypt(s.last_name, '####salt####', '###encryption mode###'), 'escape'), encode(decrypt(s.first_name, '####salt####', '###encryption mode###'), 'escape')
Revised query (doesn't work; commented additions below)
SELECT z.conditionname, x.name AS domainname, d.decisionName,
c.firstname AS counselor_first_name, c.lastname AS counselor_last_name,
o.name AS organization_name,
encode(decrypt(s.start_time, '####salt####', '###encryption mode###'), 'escape') AS start_time,
encode(decrypt(s.end_time, '####salt####', '###encryption mode###'), 'escape') AS end_time,
encode(decrypt(s.is_complete, '####salt####', '###encryption mode###'), 'escape') AS is_complete,
s.parent_session_id
//////// ADDITION START
, (SELECT MAX(encode(decrypt(start_time, '####salt####', '###encryption mode###'), 'escape')) AS start_time
FROM tblSessions s2
WHERE encode(decrypt(s2.parent_session_id, '####salt####', '###encryption mode###'), 'escape') = encode(decrypt(s.parent_session_id, '####salt####', '###encryption mode###'), 'escape') )
//////// ADDITION END
FROM tblDecisions d
INNER JOIN tblSessions s ON encode(decrypt(s.decision_id, '####salt####', '###encryption mode###'), 'escape') = d.decisionid
INNER JOIN tblCounselors c ON encode(decrypt(s.counselor_ck, '####salt####', '###encryption mode###'), 'escape') = c.campuskey
INNER JOIN tblCounselor_to_organization co ON co.counselor_id = c.counselorid
INNER JOIN tblOrganizations o ON o.organizationid = co.organization_id
INNER JOIN tblDomains x ON x.domainid = d.domain_id
INNER JOIN tblConditions z ON z.conditionid = x.condition_id
AND encode(decrypt(s.start_time, '####salt####', '###encryption mode###'), 'escape') >= '2012-01-01 00:00:00'
AND encode(decrypt(s.is_complete, '####salt####', '###encryption mode###'), 'escape') = 'true'
/////// ADDITION START
AND NOT EXISTS (
SELECT 1
FROM tblSessions s1
WHERE encode(decrypt(s1.parent_session_id, '####salt####', '###encryption mode###'), 'escape') = encode(decrypt(s.sessionid, '####salt####', '###encryption mode###'), 'escape') )
AND (
( encode(decrypt(s.parent_session_id, '####salt####', '###encryption mode###'), 'escape') IS NULL) OR
( encode(decrypt(s.start_time, '####salt####', '###encryption mode###'), 'escape') = (
SELECT MAX(encode(decrypt(start_time, '####salt####', '###encryption mode###'), 'escape')) AS start_time
FROM tblSessions s2
WHERE encode(decrypt(s2.parent_session_id, '####salt####', '###encryption mode###'), 'escape') = encode(decrypt(s.parent_session_id, '####salt####', '###encryption mode###'), 'escape')
)
)
)
///////// ADDITION END
ORDER BY encode(decrypt(s.start_time, '####salt####', '###encryption mode###'), 'escape'), encode(decrypt(s.last_name, '####salt####', '###encryption mode###'), 'escape'), encode(decrypt(s.first_name, '####salt####', '###encryption mode###'), 'escape')
I understand the error message, but that can't be the actual issue since all additions to the query have been properly decoded. Am I missing something obvious?
The question mentions that parent_session_id is type INTEGER but it is passed as the first argument to decrypt in the snippet below, unlike the rest of the code that seem to pass only bytea fields there.
decrypt(s.parent_session_id, '####salt####', '###encryption mode###')
This is likely to provokes the error mentioned, since there's no flavor of decrypt that takes an integer as the first argument (from the error message, could be confirmed with \df decrypt in psql)
Are you sure these session IDs are encrypted?

How to formulate T-SQL to exclude duplicates?

I am trying to develop a query to just return non-duplicate records so that I can add these to my database, but I keep getting the duplicate record error.
I tried your solution but am still getting duplicate error problem. I deleted the 35 rows which were duplicate. What else could be causing this? Here is my query. Part of the confusion I think is that measureid is a single column in j5c_MasterMeasures, but this value comes from two fields in j5c_ListBoxMeasures_Sys.
CREATE TABLE #GOOD_RECORDS3 (STUDENTID VARCHAR(50), MEASUREDATE SMALLDATETIME, MEASUREID VARCHAR(100),
score_10 VARCHAR(100))
INSERT INTO #GOOD_RECORDS3
select A.studentid, A.measuredate, B.measurename+' ' +B.LabelName, A.score_10
from [J5C_Measures_Sys] A join [J5C_ListBoxMeasures_Sys] B on A.MeasureID = B.MeasureID
except
select A.studentid, A.measuredate, B.measurename+' ' +B.LabelName, A.score_10
from [J5C_Measures_Sys] A join [J5C_ListBoxMeasures_Sys] B on A.MeasureID = B.MeasureID
GROUP BY A.studentid, A.measuredate, B.measurename, B.LabelName, A.score_10
having COUNT(A.score_10) > 1
delete #GOOD_RECORDS3
from #GOOD_RECORDS3 a
join sysobjects so on so.name = 'J5C_Measures_Sys' AND so.type = 'u'
join syscolumns sc on so.id = sc.id and sc.name = 'score_10'
join [J5C_MeasureNamesV2_Sys] v on v.Score_field_id = sc.name
WHERE A.SCORE_10 IS NOT NULL AND A.STUDENTID IS NOT NULL AND A.MEASUREID IS NOT NULL
and exists (select 1 from J5C_MasterMeasures M
where M.StudentID = A.StudentID
and M.MeasureID = A.MeasureID)
Insert into J5C_MasterMeasures (studentid, measuredate, measureid, nce)
select A.studentid, A.measuredate, a.MEASUREID, A.score_10
from #GOOD_RECORDS3 a
join sysobjects so on so.name = 'J5C_Measures_Sys' AND so.type = 'u'
join syscolumns sc on so.id = sc.id and sc.name = 'score_10'
join [J5C_MeasureNamesV2_Sys] v on v.Score_field_id = sc.name
WHERE A.SCORE_10 IS NOT NULL AND A.STUDENTID IS NOT NULL AND A.MEASUREID IS NOT NULL
You have not menstioned the specifics of the unique constraint on J5C_MasterMeasures. Therefore, I assumed that all four columns being inserted were part of the constraint. In addition, your use of Except leads me to believe that you are using SQL Server 2005 or later. In addition, it is not clear how the join to J5C_MeasureNamesV2_Sys fits into the design or solution.
With GoodRecords As
(
Select A.StudentId
, A.measuredate
, B.measurename+ ' ' +B.LabelName
, A.score_10 As NCE
From [J5C_Measures_Sys] A
Join [J5C_ListBoxMeasures_Sys] B
On A.MeasureID = B.MeasureID
Where A.StudentId Is Not Null
And A.Score_10 Is Not Null
And A.MeasureId Is Not Null
Group By A.StudentId
, A.MeasureDate
, B.MeasureName+ ' ' +B.LabelName
, A.score_10
Having Count(A.Score_10) = 0
)
Insert J5C_MasterMeasures ( StudentId, MeasureData, MeasureId, NCE )
Select GR.StudentId, GR.MeasureData, GR.MeasureId, GR.NCE
From GoodRecords As GR
Join [J5C_MeasureNamesV2_Sys] v
On v.Score_field_id = 'Score_10'
Where Not Exists (
Select 1
From J5C_MasterMeasures As J1
Where J1.StudentId = GR.StudentId
And J1.MeasureData = GR.MeasureData
And J1.MeasureId = GR.MeasureId
And J1.NCE = GR.NCE
)