How to convert sql limit query to linq lambda? - asp.net

Here's an example that I want to convert to lambda query:
SELECT TOP(5) Pbschedules.s_id, Pbschedules.date, Pbworth2.worth, Pbschedules.pb_id
FROM Pbschedules INNER JOIN Pbworth2 ON Pbschedules.pb_id = Pbworth2.pb_id
ORDER BY s_id desc

var query = database.Pbschedules// your starting point - table in the "from" statement
.Join(database.Pbworth2, // the source table of the inner join
pbs=> pbs.pb_id, // Select the primary key (the first part of the "on" clause in an sql "join" statement)
worth=> worth.pb_id, // Select the foreign key (the second part of the "on" clause)
(pbs, worth) => new { PbsID = pbs.s_id, Worth = worth.worth /*other columns*/ }) // selection
.OrderByDescending(x => x.s_id)
.Take(5);

var myData = (from valuesPbs in Pbschedules join valuesPbw in Pbworth2
on valuesPbs.pb_id equals valuesPbw.pb_id
orderby valuesPbs.s_id descending
select valuesPbs
).Take(5);

Related

Select value from table where the name is stored in another table

I have below view which uses get_rationalized_ip_adr function to retrieve some value given as input the nodeid from NODE table.
CREATE OR REPLACE VIEW A_DEVICE AS
SELECT NODE.NAME AS DEVICE
, NODETYPE.TABLENAME AS TABLENAME
, ext_a_device.get_rationalized_ip_adr(NODE.NODEID) AS IPADDRESS
, COALESCE(LOC_SITE.OS_EASTING, LOC_RAILWAY.OS_EASTING, LOC_SIGNALBOX.EASTING) AS OS_EASTING
, COALESCE(LOC_SITE.OS_NORTHING, LOC_RAILWAY.OS_NORTHING, LOC_SIGNALBOX.NORTHING) AS OS_NORTHING
FROM NODE NODE
JOIN NODETYPE NODETYPE
ON NODE.NODE2NODETYPE = NODETYPE.NODETYPEID;
I had to add the function in the select stmt in order to get ipaddresses that are present in some other tables, tables which have the name stored in NODETYPE table.
For example this is a screen shot form nodetype table. So the get_rationalized_ip_adr calls an API that does the fetching from NR_NODE_DDF for each nodeid passed to it.
get_rationalized_ip_adr function just calls an API with the nodeid input and returns the ip_adr for the respective node.
FUNCTION get_rationalized_ip_adr( pin_node_id IN NUMBER)
RETURN VARCHAR2 IS
ln_errorcode NUMBER;
ls_errortext VARCHAR2(200);
ls_result VARCHAR2(200);
BEGIN
pkggeneral.getobjectattribute( o_errorcode => ln_errorcode
, o_errortext => ls_errortext
, i_dimobject => pkgdimensionconstants.dimensionObject_Node
, i_objectid => pin_node_id
, i_attribute => 'IP_ADDRESS'
, o_result => ls_result);
RETURN ls_result;
END get_rationalized_ip_adr;
Now the problem for example is that this select statement is taking around 90 seconds, which is too much.
SELECT * FROM A_DEVICE ad where ad.ipaddress = '10.16.52.152'
As I understood switching between sql and pl-sql context is the problem of this time to run.
Can anyone think of another solution to decrease this time??
You need to replace your function call with join with a table which stores IP addresses.
CREATE OR REPLACE VIEW A_DEVICE AS
SELECT NODE.NAME AS DEVICE
, NODETYPE.TABLENAME AS TABLENAME
, t.IPADDRESS
, COALESCE(LOC_SITE.OS_EASTING, LOC_RAILWAY.OS_EASTING, LOC_SIGNALBOX.EASTING) AS OS_EASTING
, COALESCE(LOC_SITE.OS_NORTHING, LOC_RAILWAY.OS_NORTHING, LOC_SIGNALBOX.NORTHING) AS OS_NORTHING
FROM NODE NODE
JOIN NODETYPE NODETYPE
ON NODE.NODE2NODETYPE = NODETYPE.NODETYPEID
join table_with_ip_address t
on ...;
Also, make sure you have required indexes on fields which you use for the join.

Is there a way to select a columns from a joined table without explicitly listing all columns?

I'm trying to use JoinSqlBuilder to select a data from one of the joined tables, and can't find a way to do that unless I list all columns from that table. Hopefully I'm missing something and it actually can be done.
This is approximately what I have:
var sql = new JoinSqlBuilder<Product, Product>()
.Join<Product, Customer>(src => src.Id, dst => dst.Id)
.Where<Customer>(x => x.Id == Id);
and I want to select everything from a product table. The query above throws an exception complaining about column name collisions, so its clearly does a select from both tables.
Edit: In the end I want to have this sql (never mind the design, its not a real thing):
select
p.* //<-- This is the piece that I'm struggling with
from product p inner join customer c on p.id on c.productId
where blah;
Looks like OrmLite want me to explicitly list all columns I want to return, which I want to avoid.
Note: I'm using 3.9.71 of servicestack. I've not looked at the 4.0 implementation yet.
I think you have a FK relationship problem with your join. Assuming that a product has a customer FK named (CustID), it'd look like this. Additionally, you'd need a POCO to represent the result set, if you are returning a "combination" of the results. I don't think you'll want to return both "ID" columns, and instead return a FK column.
return _factory.Run<ProductCustomer>(conn=>
{
var jn = new JoinSqlBuilder<Product, Customer>();
jn = jn.Join<Product, Customer>(srcProd => srcProd.CustId,
dstCust => dstCust.Id, // set up join Customer.id -> Product.CustId
p => new { p.Id, p.OtherField}, // product table fields returned
c => new { c.Name, c.AddressId}, // customer fields returned
null, //where clause on the product table
cust=>cust.Id = customerId // where clause on the customer table
);
var sql = jn.ToSQL();
return conn.FirstOrDefault<ProductCustomer>(sql);
}
Hope this helps.
Edit: After your Edit, try this:
// set up join Customer.id -> c.ProductId
jn = jn.Join<Product, Customer>(srcProd => srcProd.Id, dstCust => dstCust.productId)
.Where<Customer>(c=>c.Id == custIdParameter);
var sql = jn.ToSql();
You can add a ".Where" again for the
Where<Product>(p=>p.id == foo);
if you need to add more product with your BLAH. This should get you close.
Have you tried the SelectAll extension method?
var sql = new JoinSqlBuilder<Product, Product>()
.Join<Product, Customer>(src => src.Id, dst => dst.Id)
.SelectAll<Product>()
.Where<Customer>(x => x.Id == Id);

selecting only max clause without group by properties in subquery using Nhibernate

I have SQL query like this:
select * from dbo.table1 where Id in
(
select max(id) as id from dbo.table1 group by prop1, prop2, prop3
)
I want to create NHibernate query which is be able to do this for me. I tried to use QueryOver but it doesn't work. Do you have any suggestions how to do it?
NHibernate supports even this kind of queries. Please, see more in documentation: 15.8. Detached queries and subqueries. We just have to split the query (as in your SQL snippet) into two parts:
inner select
the select with the IN clause
Let's assume, that the dbo.table1 in the Questin is mapped into MyEntity.
To create inner select, let's use the DetachedCriteria
EDIT (extended with the Group by, SqlGroupProjection)
There is an extract of the SqlGroupProjection method:
A grouping SQL projection, specifying both select clause and group by
clause fragments
// inner select
DetachedCriteria innerSelect = DetachedCriteria
.For(typeof(MyEntity))
.SetProjection(
Projections.ProjectionList()
.Add(
Projections.SqlGroupProjection(
" MAX(ID) ", // SELECT ... max(ID) only
" Prop1, Prop2, Prop3", // GROUP BY ... property1, p2...
new string[] {"ID"}, // could be empty, while not used for
new IType[] { NHibernate.NHibernateUtil.Int32 } // transformation
)
)
;
Note: I've provided even the last two paramters, but in this case they could be empty: new string[], new IType[] {}. These are used only for Transformation (materialization from data into entity). And this is not the case, we are just building inner select...
// the select with IN clause
var result = session.CreateCriteria(typeof(MyEntity))
.Add(Subqueries.PropertyIn("ID", innerSelect))
.List<MyEntity>();
Also related could be 15.7. Projections, aggregation and grouping

LINQ - EF join difficulty

I have two tables:
Phase :
long ID
string Name
and another Activity :
long ID
string Name
long PhaseID
I already know the name of the phases and I want to get the activity for those particular phases. Do i add PhaseName to the activity table or do I do it through join in LINQ?
Maybe something like this?
var query = from a in entities.Activities
join p in entities.Phases on a.PhaseId equals p.Id
where p.Name == "Preplanning"
... and here im not sure how to finish this query..
Thanks for your help!
The code that you've provided will use an Inner Join to find all Activities where the Phase with Name "Preplanning" exists.
To finish your query you need to add a select clause.
var query = from a in entities.Activities
join p in entities.Phases on a.PhaseId equals p.Id
where p.Name == "Preplanning"
select a.Name
will return IEnumerable<string> of all activity names.
Just select activity, as you want:
var query = from a in entities.Activities
join p in entities.Phases on a.PhaseId equals p.Id
where p.Name == "Preplanning"
select a;
Here is how query expression should look like:
A query expression must begin with a from clause and must end with a select or group clause. Between the first from clause and the last select or group clause, it can contain one or more of these optional clauses: where, orderby, join, let and even additional from clauses. You can also use the into keyword to enable the result of a join or group clause to serve as the source for additional query clauses in the same query expression.
Same as puzzling image:
With method syntax you don't need to end query with something special:
var query = entities.Phases
.Where(p => p.Name == "Preplanning")
.Join(entities.Activities, p => p.Id, a => a.PhaseId, (p,a) => a);
No need to do a join if you only need data from one of the tables. You can apply a filter instead:
var q = entities.Activities.Where(a =>
entities.Phases.Any(p => a.PhaseId == p.Id && p.Name == "Preplanning"));

ASP.NET: Linq2SQL: selecting all names matching an id

Got 2 tables: db.Tags (ID, TagName) and db.Names (ID, Name, TagID).
I want to fetch all db.Tags rows, and all the Names matching the TagID.
So it will look like
ID - TagName - Names
1 - tag1 - name1, name2, name3
2 - tag2 - name4, name5, name6
Is this possible in one (long) linq query?
or do I have to get all the tags, then do foreach tag, get all the names, then do foreach names to put them in a one long string..
Thanks in advance!
EDIT:
Okay see my comment on the second answer (first one up..), this is what i tried but i get some errors in compiler:
var tags =
from t in db.Tags
orderby t.Priority ascending
select new {
t.ID,
t.Name,
t.Priority,
Places = String.Join(", ",
(from p in db.Places
join o in db.TagToPlaces on new {
p.ID,
t.ID
}
equals new {
o.PlaceId,
o.TagId
}
select p.Name
).ToArray()
)
}
);
I think this is what you're after:
var query =
from t in db.Tags
select new
{
t.ID,
t.TagName,
Names = String.Join(", ",
(from n in db.Names
where n.TagID == t.ID
select n.Name)
.ToArray()),
};
With this I get the same sort of output that you gave in your question. I also understood that you want to output the tag id and name even when there are no associated name records - my query does that.
Now depending on if you're using EF or LINQ-to-SQL or something else you may need to add .ToArray() to the db.Tags & db.Names references to force the database query to occur.
If you have a large number of tag records you'll find you have a large number of queries going to the database. You could make this change to reduce it to only two queries:
var tags = db.Tags.ToArray();
var names = db.Names.ToArray();
var query =
from t in tags
select new
{
t.ID,
t.TagName,
Names = String.Join(", ",
(from n in names
where n.TagID == t.ID
select n.Name)
.ToArray()),
};
Now you just need to make sure that your data fits into memory - but it sounds like it should. I hope this helps.
Since the concat is a pain in TSQL, I would query the 3 values "as is", and format from there:
var list = (from tag in db.Tags
join name in db.Names
on tag.ID equals name.TagId
orderby tag.ID
select new { tag.ID, tag.TagName, name.Name }).ToList();
for example, if I wanted the names by tag-id, I could do:
var namesByTag = list.ToLookup(row => row.ID, row => row.Name);
(or whatever else you choose)

Resources