Sql query to get newest comment added joined 3 tables - c#

I am trying to make a sql query, that gets me the registration_timestamp of the newest comment.
By supplying a category id.
I have three tables. ( seen below with the fields that should be needed)
Ctm_Comments{
Id,
Page_ID,
Registration_Timestamp
}
Ctm_Forum_Categories{
Id
}
Ctm_Forum_Posts{
Id,
FK_Category_ID
}
I have tried the following, and it returns zero results.
var query = from p in Ctm_Forum_Posts
join c in Ctm_Forum_Categories on p.FK_Categori_ID equals c.Id
join ctm in Ctm_Comments on p.Id equals ctm.Page_ID
where c.Id == 1
select ctm.Reqistration_timestamp;
SQL Queries like these are not my strong suit, so i hope someone here can help out.
Ended up with this, based on the response from accepted answer.
var query = (from comments in Ctm_Comments
join posts in Ctm_Forum_Posts on comments.Page_ID equals posts.Id
join category in Ctm_Forum_Categories on posts.FK_Categori_ID equals category.Id
where category.Id == 1
orderby comments.Reqistration_timestamp descending
select comments.Reqistration_timestamp).FirstOrDefault();

SQL (MS SQL) Query needed is
SELECT TOP 1 [Registration_Timestamp]
FROM [dbo].[Ctm_Comments] AS C
INNER JOIN [dbo].[Ctm_Forum_Posts] AS P ON C.Page_ID = P.Id
INNER JOIN [dbo].[Ctm_Forum_Categories] AS CAT ON CAT.Id = P.Category_ID
WHERE CAT.Id = 1
ORDER BY C.Registration_Timestamp DESC
and this is if we accept that PageID (of Comments Table) is the Post Id. Otherwise, you are missing the PostId Column in the table of Comments which should be the join point
Run the Script below in SQL Server Studio for verification
CREATE TABLE [dbo].[Ctm_Comments] ( [Id] [int] NULL,[Page_ID] [int] NULL,[Registration_Timestamp] [datetime] NULL) ON [PRIMARY]
CREATE TABLE [dbo].[Ctm_Forum_Categories] ( [Id] [int] NULL) ON [PRIMARY]
CREATE TABLE [dbo].[Ctm_Forum_Posts] ( [Id] [int] NULL,[Category_ID] [int] NULL) ON [PRIMARY]
INSERT INTO [dbo].[Ctm_Comments] VALUES (1, 1, '2020-10-23 13:12:55')
INSERT INTO [dbo].[Ctm_Comments] VALUES (2, 1, '2020-10-26 12:12:55')
INSERT INTO [dbo].[Ctm_Comments] VALUES (3, 1, '2020-10-26 12:25:55')
INSERT INTO [dbo].[Ctm_Comments] VALUES (4, 1, '2020-10-26 13:12:55')
INSERT INTO [dbo].[Ctm_Forum_Categories] VALUES (1)
INSERT INTO [dbo].[Ctm_Forum_Posts] VALUES (1, 1)
SELECT TOP 1 [Registration_Timestamp]
FROM [dbo].[Ctm_Comments] AS C
INNER JOIN [dbo].[Ctm_Forum_Posts] AS P ON C.Page_ID = P.Id
INNER JOIN [dbo].[Ctm_Forum_Categories] AS CAT ON CAT.Id = P.Category_ID
WHERE CAT.Id = 1
ORDER BY C.Registration_Timestamp DESC
DROP TABLE [dbo].[Ctm_Comments]
DROP TABLE [dbo].[Ctm_Forum_Categories]
DROP TABLE [dbo].[Ctm_Forum_Posts]
the Result is 2020-10-26 13:12:55.000

When you fix the "my query returns 0 results" part, I'd suggest something like this:
var mostRecentCommentTimestamp = query.Max();
But as you've only selected timestamps, this can only tell you the max timestamp, nothing else about the comment
If you want the whole most recent comment swap the select for an order by descending on the timestamp and take the first*, or install morelinq and use their MaxBy
*Edit, like this:
var query = from p in Ctm_Forum_Posts
join c in Ctm_Forum_Categories on p.FK_Categori_ID equals c.Id
join ctm in Ctm_Comments on p.Id equals ctm.Page_ID
where c.Id == 1
orderby ctm.Reqistration_timestamp descending
select ctm;
var firstComment = query.First();
All this said, at the moment you say your query produces no results; you need to fix that (the joins are wrong, or there is no category 1, or the db is missing data) before you can get a max/orderby of anything

Related

SQL query distinct issue

I have written the below query to list all the rows in table [HRSurvey]
which empid is only present in empsurveyselection. Both table have empid columns.
But i am not able to get the proper results because there
might be multiple empid for same surveyid in empsurveyselection table.
But this query works fine when there is only one empid for each surveyid in empsurveyselection table.
Could you please rewrite the query to list the all the rows in the table HRSurvey where the empid are there in empsurveyselection ?
SELECT hrs.*
FROM [HRSurvey] hrs
Left Join [HRSurveyEmployee] hse
ON hse.EmpID = hrs.EmpID
LEFT Join Surveys s
ON s.surveyid = hse.surveyid
WHERE hrs.empid IN (
SELECT empid FROM [HRSurveyEmployee] where surveyid = s.surveyid
) and sempid
in ( select DISTINCT empid FROM empsurveyselection WHERE deptid=9 and surveyid = s.surveyid)
You can write as:
SELECT hrs.col1, -- Worst Practice to use * in production code to pull data
hrs.col12 -- Use explicit column names instead
FROM [HRSurvey] hrs
INNER JOIN [HRSurveyEmployee] hse ON hse.EmpID = hrs.EmpID
INNER JOIN [Surveys] s ON s.surveyid = hse.surveyid
INNER JOIN [empsurveyselection]ess ON ess.deptid=9
AND ess.surveyid = s.surveyid AND hrs.sempid = ess.empid
Please try with the below query....
select a.*
from HRSurvey a
where empid exists (select 1
from empsurveyselection b
where a.Empid = b.Empid)
Thanks for the help! Actually issue was not with the query. Issue was with the data and i fixed it.

Query taking too long to execute in LINQ

I've written a query which should take all the rows from one table and do a subquery to a second table pulling only one value from the most recent record. In SQL Server the query takes about 15 seconds to execute and the LINQ query takes close to 2 minutes. Can someone help me with translating the SQL to LINQ, I must have done something wrong along the way.
The SQL:
SELECT a.isrunning,
worktype = (
SELECT TOP 1
w.worktype
FROM dbo.workorder w WITH (NOLOCK)
WHERE w.assetnum = a.assetnum
ORDER BY w.statusdate DESC
),
a.status,
*
FROM dbo.asset a WITH (NOLOCK)
WHERE a.assetnum IN ('list', 'of', 'asset', 'numbers')
The LINQ Query:
(
from a in db.assets
let wo = (
from w in db.workorders
where w.assetnum == a.assetnum
orderby w.statusdate descending
select w).FirstOrDefault()
where aliasStrings.Contains(a.assetnum)
select new AssetWithWorkType {
...
}
);
It is recommended to have indexes on foreign keys. Also indexes that covers filtering and ordering clauses. So I suggest you to create the following 3 indexes:
CREATE NONCLUSTERED INDEX [IDX_workorder_statusdate] ON dbo.workorder(statusdate)
CREATE NONCLUSTERED INDEX [IDX_workorder_assetnum] ON dbo.workorder(assetnum)
If assetnum column in asset table is not the primary key then additionally:
CREATE NONCLUSTERED INDEX [IDX_asset_assetnum] ON dbo.asset(assetnum)
You can create a temp table for the correlated subquery results, and then join it later. Syntax is not correct, as I dont have your table schemas or data, but the idea is the same.
CREATE TABLE #workTypes (worktype VARCHAR(X), assetnum VARCHAR(x))
INSERT INTO #workTypes
SELECT TOP 1 worktype, assetnum FROM dbo.workorder ORDER BY statusdate DESC
SELECT a.isrunning,
b.worktype,
a.status,
*
FROM dbo.asset a WITH (NOLOCK)
INNER JOIN #worktypes b
ON a.assetnum = b.assetnum
WHERE a.assetnum IN ('list', 'of', 'asset', 'numbers')
How about:
SELECT a.isrunning,
w.worktype,
cnt = count(*)
FROM dbo.asset a WITH (NOLOCK)
INNER JOIN dbo workorder w WITH (NOLOCK) on w.assetnum = a.assetnum
WHERE a.assetnum IN ('list', 'of', 'asset', 'numbers')
This would give you a count of worktypes for each asset and might allow the database server to optimize more efficiently. Also consider adding indices or using a temp table as other answers have suggested.

sql query with complicated join to get unique records list

I need a query that select customer table with right cardId by applied the below cases.
If you have any suggestions, please share.
Possible cases are:
Only one records found - easy, use the Card_id found
No records found - leave blank
More than one record found - use the Card_id that starts with 2000 if available, otherwise pick the one with latest created date (in CustomerCards table)
Customer Table:
ID CardID
1 200132
2 263987
3 100789
..
CustomerCards table
CustomerId CardID CreatedOn
1 209890 12/11/2014
1 200132 12/12/2014
1 100732 11/10/2014
2 168902 12/11/2014
2 263987 15/01/2015
I've started with left join:
select ct.* from dbo.Customer ct
left join dbo.CustomerCard cc
on ct.id = cc.customerId
And a bit stuck after that.
A start
;with cte1 as
(
select cc.CustomerId, cc.CardID, cc.CreatedOn
from dbo.CustomerCard cc
group by cc.CustomerId, cc.CardID, cc.CreatedOn
having count(*) = 1
), cte200 as
(
select cc.CustomerId, cc.CardID, max(cc.CreatedOn)
from dbo.CustomerCard cc
group by cc.CustomerId, cc.CardID
where cc.CardID like '2000%'
)
select cte1
union
select cte2000
union
select ct.ID, ct.CardID, '1/1/1900' as CreatedOn
from dbo.Customer ct
left join dbo.CustomerCard cc
on ct.id = cc.customerId
where cc.customerId is null
union
select cc.ID, cc.CardID, max(cc.CreatedOn)
from dbo.CustomerCard cc
left join cte1
on cte1.customerId = cc.customerId
left join cte2000
on cte2000.customerId = cc.customerId
where cte1.customerId is null
and cte2000.customerId is null
group by cc.ID, cc.CardID

Forcing linq to perform inner joins

I'm trying to force Linq to preform an inner join between two tables. I'll give an example.
CREATE TABLE [dbo].[People] (
[PersonId] [int] NOT NULL,
[Name] [nvarchar](MAX) NOT NULL,
[UpdatedDate] [smalldatetime] NOT NULL
... Other fields ...
)
CREATE TABLE [dbo].[CompanyPositions] (
[CompanyPositionId] [int] NOT NULL,
[CompanyId] [int] NOT NULL,
[PersonId] [int] NOT NULL,
... Other fields ...
)
Now I'm working with unusual database as there's a reason beyond my control for people to be missing from the People table but have a record in CompanyPositions. I want to filter out CompanyPositions with missing People by joining the tables.
return (from pos in CompanyPositions
join p in People on pos.PersonId equals p.PersonId
select pos).ToList();
Linq sees this join as redundant and removes it from the SQL it generates.
SELECT
[Extent1].[CompanyPositionId] AS [CompanyPositionId],
[Extent1].[CompanyId] AS [CompanyId],
....
FROM [dbo].[CompanyPositions] AS [Extent1]
However it's not redundant in my case. I can fix it like this
// The min date check will always be true, here to force linq to perform the inner join
var minDate = DateTimeExtensions.SqlMinSmallDate;
return (from pos in CompanyPositions
join p in People on pos.PersonId equals p.PersonId
where p.UpdatedDate >= minDate
select pos).ToList();
However this now creates a needless where clause in my SQL. As a purest I'd like to remove this. Any idea's or does the current database design tie my hands?
Since PersonId is declared NOT NULL (and I assume it is declared as an FK to People) then I'm not sure how you could have a CompanyPosition with a person that is not assigned; and Linq can't see how you can eiter, which is why as you have observed Linq considers the join redundant.
If you're using LinqToSql, you can use LoadWith similar to this:
var context = new MyDataContext();
var options = new DataLoadOptions();
options.LoadWith<People>(x => x.CompanyPositions);
context.LoadOptions = options;
I don't know how to force linq to use a join. But the following statment should give you the required result.
return (from pos in CompanyPositions
where (p in People select p.PersonId).Contains(pos.PersonId)
select pos).ToList();
ClientSide transformation:
(
from pos in CompanyPositions
join p in People on pos.PersonId equals p.PersonId
select new {pos, p}
).ToList().Select(x => x.pos);
More direct filtering:
from pos in CompanyPositions
where pos.People.Any()
select pos

LINQ to Entities find top records from ordered groupings

I have a problem that I know how to solve in SQL but not with Linq to Entities.
My data looks like this:
ID GROUP TIMESTAMP
-- ----- ---------
1 A 2011-06-20
2 A 2011-06-21
3 B 2011-06-21
4 B 2011-06-22
5 B 2011-06-23
6 C 2011-06-30
I want to retrieve all the Entity objects (not just the ID) such that I am only getting the most recent record from each group. (ie. the records with ids 2, 5, 6)
In SQL I would do something like this:
SELECT * FROM my_table a
WHERE a.timestamp =
(SELECT MAX(timestamp) FROM my_table b
WHERE a.group = b.group)
(For the sake of this question you can assume that timestamp is unique within each group).
I'd like to do this query against a WCF Data Service using Linq to Entities but I can't seem to have a nested query that references the outside query like this. Can anyone help?
Possibly not as clean and efficient as the hand written version but here's what I came up with
var q = from a in db.MyEntities
where a.Timestamp == (from b in db.MyEntities
where b.Group == a.Group
select b.Timestamp).Max()
select a;
which translates into this SQL
SELECT
[Project1].[Id] AS [Id],
[Project1].[Group] AS [Group],
[Project1].[Timestamp] AS [Timestamp]
FROM ( SELECT
[Extent1].[Id] AS [Id],
[Extent1].[Group] AS [Group],
[Extent1].[Timestamp] AS [Timestamp],
[SSQTAB1].[A1] AS [C1]
FROM [MyEntities] AS [Extent1]
OUTER APPLY
(SELECT
MAX([Extent2].[Timestamp]) AS [A1]
FROM [MyEntities] AS [Extent2]
WHERE [Extent2].[Group] = [Extent1].[Group]) AS [SSQTAB1]
) AS [Project1]
WHERE [Project1].[Timestamp] = [Project1].[C1]
Hi try to use linqer that will convert your sql statements to linq query.
Linqer
Best Regards
This should work:
var query = db.my_table
.GroupBy(p=>p.group)
.Select(p=>p.OrderByDescending(q=>q.timestamp).First());
Here you go.A simple way to do.
var result = (from x in my_table
group x by x.Group into g
select new
{
g.Key,
timestamp = g.Max(x => x.TimeStamp),
g //This will return everything in g
});

Categories