5

I have the following in linq-to-entities

clientprojects = (from p in this.SAPMappingEntities.SAP_Master_Projects 
join c in this.SAPMappingEntities.SAP_Master_ProjectPartners on c.project_no equals p.project_no
where c.partner_name.Contains(clientstring)
orderby p.start descending 
select new ClientProjects { client = c.partner_name, location = c.city +", "+c.region, project_no = c.project_no, start_dt = p.start, end_dt = p.finish }).Take(50).ToList();

I would like change this query so that for each SAP_Master_Project only get the SAP_Master_ProjectPartners record which has the latest update_dt. How can I do this?

EDIT

There's a project table with a project number and project details including project start and end dates. There's a project partners table with the project partner number, name, project number, update date and other details.

SAP_MASTER_PROJECT

project_no

start

finish

SAP_MASTER_PROJECTPARTNERS

partner_no

project_no

partner_name

city

region

update_dt

When the user enters "ABC" into a text box, the info I want to return is the project number, project start date, project end date plus project partner name, city, and state from the last project partner record for the last 50 projects (based on start date) where the project partner name contains or is like "ABC".

I'm sure there's more than one way to do this, but his SQL gives me the results that I need:

SELECT TOP 50 p.project_no, p.start, p.finish, c.partner_name, c.city, c.region
FROM 
(select pp.project_no, pp.partner_name, pp.city, pp.region
from SAP_Master_ProjectPartners pp
where pp.partner_name LIKE @clientstring AND pp.update_dt = (select max(pp1.update_dt)
                       from SAP_Master_ProjectPartners pp1
                       where pp1.project_no = pp.project_no)) c
join SAP_Master_Projects p
on (p.project_no = c.project_no)
ORDER BY p.start DESC

EDIT #2 That sql actually returns a few items which have the same update_dt, so I modified the sql to below. Still struggling to convert to linq.

SELECT TOP 50 p.project_no, p.start, p.finish, c.partner_name, c.city, c.region, c.update_dt, c.row_id
FROM SAP_Master_Projects p
join
(select pp.project_no, pp.partner_name, pp.city, pp.region, pp.update_dt, pp.row_id
from SAP_Master_ProjectPartners pp
where pp.partner_name LIKE @clientstring AND pp.row_id = (select TOP 1 row_id
                       from SAP_Master_ProjectPartners pp1
                       where pp1.project_no = pp.project_no order by update_dt DESC)) c
on (p.project_no = c.project_no) where p.active_flag = 1
ORDER BY p.start DESC
Yuval Itzchakov
  • 146,575
  • 32
  • 257
  • 321
RememberME
  • 2,092
  • 4
  • 37
  • 62
  • Can you provide some detail on the structure of your entities? You mention update_dt, but its hard to determine exactly where that is. Also, can you clarify if you need the ClientProjects to be included in this query? – chemicalNova Oct 27 '11 at 03:50
  • There is one SAP_Master_Project entry per project. There are multiple SAP_Master_ProjectPartners entries per project. I want to join the SAP_Master_Project with the SAP_Master_ProjectPartners with the last SAP_Master_ProjectPartners.update_dt. For each project/project partner combination, I want to return one entry (the last one). – RememberME Oct 27 '11 at 03:57
  • One thing that doesn't make sense about your schema to me is that it seems like you are trying to provide a history, but you're really creating the DB like a many-to-one relationship. Seems like a bad DB design, since you should really keep a history in a separate table (maybe even a separate model). You can never model multiple partners for a single project if you do the change you're trying to do here. And partners can only have a single project. Seems like you should really have a third table with the relationships, making it many to many – Merlyn Morgan-Graham Oct 27 '11 at 05:40
  • This could allow you to keep the history the way you have it, as you could just update the mapping to point to the latest one. – Merlyn Morgan-Graham Oct 27 '11 at 05:42
  • These tables have been in existence for a very long time and are used by multiple applications. I just want to query this data to display it on the screen to the user. – RememberME Oct 27 '11 at 15:02

3 Answers3

10

This query would probably be simpler if you defined an entity relationship between SAP_Master_Projects and SAP_Master_ProjectPartners so the join could be implicit instead of explicit.

Edit Since you can't do that, something like this might work (using let and doing a logical join within a where clause):

var clientProjects =
    (
        from p in entities.SAP_Master_Projects
        let c = entities.SAP_Master_ProjectPartners
            .Where(cl => cl.partner_name.Contains(clientstring)
                && cl.project_no == p.project_no
                )
            .OrderBy(cl => cl.update_dt) // Todo: Might need to be descending?
            .FirstOrDefault()
        where c != null
        orderby p.start descending
        select new ClientProjects
        {
            client = c.partner_name,
            location = c.city + ", " + c.region,
            project_no = c.project_no,
            start_dt = p.start,
            end_dt = p.finish
        }
        )
    .Take(50)
    .ToList()
    ;
Merlyn Morgan-Graham
  • 58,163
  • 16
  • 128
  • 183
  • I can't set the relationship b/c it's not set in the db and I can't touch that. If I set it in the Model, then when the Model is updated it will be overwritten and other developers won't know/remember to add it back each time. – RememberME Oct 27 '11 at 04:27
  • @RememberME: Well, which part are you having a problem with then? This query still should work if you edit it to accommodate that issue, and do an explicit join. – Merlyn Morgan-Graham Oct 27 '11 at 04:39
  • How would I add the join to that? I can't join to a let. – RememberME Oct 27 '11 at 05:16
  • @RememberME: You might be able to add the join implicitly with the where clause instead. Editing the answer to show this. If it works, I have no idea what the perf is like. You might want to try something like `LinqPad` against your DB to see the SQL it generates, and talk to your DBA to make sure the query performance isn't too terrible. – Merlyn Morgan-Graham Oct 27 '11 at 06:58
  • It requires me to change .First() to .FirstOrDefault(). It's then selecting all projects with c as null. – RememberME Oct 27 '11 at 15:10
  • Guess it's doing a left outer join and I need an inner. – RememberME Oct 27 '11 at 17:51
  • Added a where c!=null and it's returning the correct results now. Not sure if that's the best way, but it works. – RememberME Oct 27 '11 at 19:16
  • @RememberME: I guess it makes sense. You won't always get a result for `c`, so you must make it `FirstOrDefault`, which then means you have to filter out rows where you don't get results by doing a `where c != null`. If you wanted to try to clean this up, you could try building out your query for partners first, get the right result, and then join the project to those results. – Merlyn Morgan-Graham Oct 27 '11 at 19:28
1

It sounds like you're trying to come up with the following query:

SELECT *
  FROM MasterProjects p
       INNER JOIN (SELECT project_no,
                          partner_name
                     FROM ProjectPartners o
                    WHERE o.update_dt = (SELECT MAX(update_dt)
                                           FROM ProjectPartners i
                                          WHERE i.project_no = o.project_no)) c
               ON p.project_no = c.project_no
              AND p.partner_name = c.partner_name

I'm not entirely sure how to translate this in to LINQ but here is my best attempt:

var clientprojects =
    from p in MasterProjects
    join c in ProjectPartners on p.project_no == c.project_no
   where c.partner_name == (from o in ProjectPartners
                           where o.project_no == c.project_no
                             and o.update_dt == (from i in ProjectParters
                                                where o.project_no = i.project_no
                                               select i.update_dt).Max()
                          select o.partner_name).First();

The above LINQ may not even compile, but hopefully it'll send you in the right direction.

Joshua
  • 8,112
  • 3
  • 35
  • 40
0

I don't speak your language, sorry. But, for instance, in MySql you might add sort by update_dt DESC LIMIT 1 can you do that or somethign similar?

Mawg says reinstate Monica
  • 38,334
  • 103
  • 306
  • 551