Complex SQL query with LINQ - c#

I am working on a CSV file and I need to get values with a specific query. It is simple with SQL but I am unable to do it with LINQ. For instance how do I write the following query with LINQ:
SELECT outer_table.SONG_COUNT, COUNT( outer_table.CLIENT_ID ) AS CLIENT_COUNT
FROM (SELECT COUNT( DISTINCT (
my_table.SONG_ID
)) AS SONG_COUNT, my_table.CLIENT_ID
FROM data AS my_table
GROUP BY my_table.CLIENT_ID
) AS outer_table WHERE outer_table.SONG_COUNT=346
GROUP BY outer_table.SONG_COUNT

Someone will need to explain to me why it's a good idea to convert sql to linq so linq can generate your sql. Use QueryFirst (disclaimer: which I wrote). Your SQL is directly executable in your c# app. Plus numerous other advantages.

Related

Basic LINQ query to SQL C#

I have this LINQ query in C# for querying a db4o database.
IEnumerable<internetRecord> searchResult = from internetRecord ie in database
where ie.GSrecordID.Contains(txtSearchString.Text)
select ie;
What would be the equivalent query in SQL? (needed for comparison purposes) I have not worked with SQL much in the past and looking at it after using LINQ for a while it seems confusing.
SELECT *
FROM MyTable
WHERE GSRecordID LIKE '%txtSearchString%'
Select * from internetrecord where GSrecordID like '%your comparison string%'
Provided internetrecord is your SQL table GSrecordID is the column of your table.
I don't know much about db40 but in standard SQL it would be:
SELECT * FROM internetRecord
WHERE GSrecordID LIKE '%txtSearchString%'
YOu can do something like this
var result = database.Where(x => x.GSrecordID.Contains(txtSearchString.Text));

LINQ to SQL will not generate sargable query

I'm using LINQ To Sql (not Entity Framework), the System.Data.Linq.DataContext library, hitting a SQL Server 2005 database and using .Net Framework 4.
The table dbo.Dogs has a column "Active" of type CHAR(1) NULL. If I was writing straight SQL the query would be:
SELECT * FROM dbo.Dogs where Active = 'A';
The LINQ query is this:
from d in myDataContext.Dogs where d.Active == 'A' select d;
The SQL that gets generated from the above LINQ query converts the Active field to UNICODE. This means I cannot use the index on the dbo.Dogs.Active column, slowing the query significantly:
SELECT [t0].Name, [t0].Active
FROM [dbo].[Dog] AS [t0]
WHERE UNICODE([t0].[Active]) = #p1
Is there anything I can do to stop Linq to Sql from inserting that UNICODE() call (and thus losing the benefit of my index on dogs.Active)? I tried wrapping the parameters using the EntityFunctions.AsNonUnicode() method, but that did no good (it inserted a CONVERT() to NVARCHAR instead of UNICODE() in the generated sql), eg:
...where d.Active.ToString() == EntityFunctions.AsNonUnicode('A'.ToString());
Linq is meant to make it easier to write queries and does not always generate optimal SQL. Sometimes when high performance is required it is more efficient to write raw SQL directly against the database, the Linq datacontext supports mapping of SQL result to entities just like linq.
In your case I would suggest writing:
IEnumerable<Dog> results = db.ExecuteQuery<Dog>(
"SELECT * FROM dbo.Dogs where Active = {0}",
'A');
This is an old question, but I bumped into this recently.
Instead of writing
from d in myDataContext.Dogs where d.Active == 'A' select d;
Write
from d in myDataContext.Dogs where d.Active.Equals('A') select d;
This will produce the desired SQL without having to resort to any of the "hacks" mentioned in other answers. I can't say why for certain.
I've posted that as a question, so we'll see if we get any good answers.
There's not much you can do to the way LINQ queries are translated into SQL statements, but you can write a stored procedure that contains your queries and call that SP as a LINQ2SQL function. This way you should get full benefit of SQL Server optimizaions
You can do a little hack (as it is often required with LINQ to SQL and EF). Declare the property as NCHAR in the dbml. I hope that will remove the need to do the UNICODE conversion. We are tricking L2S in a benign way with that.
Maybe you need to also insert the EntityFunctions.AsNonUnicode call to make the right hand side a non-unicode type.
You can also try mapping the column as varchar.

Is there an api or extension to translate IQueryable<T> lambda expressions to SQL strings?

I was reading an article on Linq to Sql and came across this:
IQueryProvider provider = new QueryProvider(database.GetCommand, database.ExecuteQuery);
IQueryable<Product> source = new Queryable<Product>(provider, database.GetTable<Product>());
IQueryable<string> results = source.Where(product => product.CategoryID == 2)
.OrderBy(product => product.ProductName)
.Select(product => product.ProductName)
.Skip(5)
.Take(10);
The author then translated the results in plain sql:
exec sp_executesql N'SELECT [t1].[ProductName]
FROM (
SELECT ROW_NUMBER() OVER (ORDER BY [t0].[ProductName]) AS [ROW_NUMBER], [t0].[ProductName]
FROM [dbo].[Products] AS [t0]
WHERE [t0].[CategoryID] > #p0
) AS [t1]
WHERE [t1].[ROW_NUMBER] BETWEEN #p1 + 1 AND #p1 + #p2
ORDER BY [t1].[ROW_NUMBER]',N'#p0 int,#p1 int,#p2 int',#p0=2,#p1=5,#p2=10
And I thought to myself, "holy cow! wouldn't it be great if there was an extension to IQueryable that would generate these strings for you when debugging?"
Anyone ever heard of anything like this, and if so, could you point me in the right direction?
Thanks!
With Linq to Sql you can call query.Provider.ToString() and this will return you text of query (btw you can watch same property in Visual Studio when debugging).
UPDATE: (complex part) How it is implemented?
Actual string generation is done by System.Data.Linq.SqlClient.SqlProvider class. It has hidden method string IProvider.GetQueryText(Expression query), which builds SQL query text based on passed expression. This method is hidden by internal interface IProvider, so it's not trivial thing to call it.
I think Linqpad can be used to translate between SQL and Linq, hope that helps.
You can set the DataContext.Log property to a TextWriter (e.g. Console.Out) to see the SQL as it is generated, but I don't think this lets you output the SQL without executing it.
A terrible hacky solution:
Use DataContext.Log as previously said, but just wrap everything in a transaction and rollback. ;p

Convert SQL query in LINQ query and move results into new datatable

I have a DataTable, and need to extract the data by using this SQL query:
SELECT code_direction, count(TP) AS CN FROM table1 WHERE
cod_time = 'A011' GROUP BY TP,code_direction;
Which is the C# LINQ equivalent query?
After it I want to move the results into a new DataTable.
I tried many examples founded around in web but no this specific logic.
Linqer is your friend!
This tool can translate SQL to LINQ. You can download it at http://www.sqltolinq.com.
Note that it's not always possible to convert a SQL query straight into a 100% equivalent LINQ query, but it should be close enough.
If you need translation in the other direction -- from LINQ to SQL -- you can use LINQPad. Download it at http://www.linqpad.net/.

Using C# to Select from SQL database Table

I have a List of UserID's and a open connection to SQL Server. How can I loop through this List and Select matching UserID with First_Name and Last_Name columns? I assume the output can be in a datatable?
many thanks
It varies slightly depending on which type of SQL you're running, but this and this should get you started.
The most expedient way of doing this would be to:
Turn the List into a string containing a comma separated list of the userid values
Supply that CSV string into an IN clause, like:
SELECT u.first_name,
u.last_name
FROM USER_TABLE u
WHERE u.userid IN ([comma separated list of userids])
Otherwise, you could insert the values into a temp table and join to the users table:
SELECT u.first_name,
u.last_name
FROM USER_TABLE u
JOIN #userlist ul ON ul.userid = u.userid
Write a function in your SQL database named ParseIntegerArray. This should convert a comma delimited string into a table of IDs, you can then join to this in your query. This also helps to avoid any SQL injection risk you could get from concatenating strings to build SQL. You can also use this function when working with LINQ to SQL or LINQ to Entities.
DECLARE #itemIds nvarchar(max)
SET itemIds = '1,2,3'
SELECT
i.*
FROM
dbo.Item AS i
INNER JOIN dbo.ParseIntegerArray(#itemIds) AS id ON i.ItemId = id.Id
This article should help you: http://msdn.microsoft.com/en-us/library/aa496058%28SQL.80%29.aspx
I've used this in the past to create a stored procedure accepting a single comma delimited varchar parameter.
My source from the C# program was a checked list box, and I built the comma delimited string using a foreach loop and a StringBuilder to do the concatenation. There might be better methods, depending on the number of items you have in your list though.
To come back to the SQL part, the fn_Split function discussed in the article, enables you to transform the comma delimited string back to a table variable that SQL Server can understand... and which you can query in your stored procedure.
Here is an example:
CREATE PROCEDURE GetSelectedItems
(
#SelectedItemsID Varchar(MAX) -- comma-separated string containing the items to select
)
AS
SELECT * FROM Items
WHERE ItemID IN (SELECT Value FROM dbo.fn_Split(#SelectedItemsIDs,','))
RETURN
GO
Note that you could also use an inner join, instead of the IN() if you prefer.
If you don't have the fn_Split UDF on your SQL Server, you can find it here: http://odetocode.com/Articles/365.aspx
I hope this helps.

Categories

Resources