How to convert this sql script in linq to entity? - sql

SELECT * INTO #Loc1
FROM LocaleStringResource
Where LanguageId = 1
SELECT * INTO #Loc2
FROM LocaleStringResource
Where LanguageId = 3
SELECT Loc1.Id, Loc1.LanguageId, Loc1.ResourceName, Loc1.ResourceValue,
Loc2.Id, Loc2.LanguageId, Loc2.ResourceName, Loc2.ResourceValue
FROM #Loc1 AS Loc1 INNER JOIN
#Loc2 AS Loc2 ON Loc1.ResourceName = Loc2.ResourceName
Update:
I have a table named - LocaleStringResource.
Columns: Id, LanguageId, ResourceName, ResourceValue,
Suppose I have 2 language in my system.
Id Language
1 English
3 Bangla
Id LanguageId ResourceName ResourceValue
1 1 Admin.Address Address
2 1 Admin.Phone Phone
51 3 Admin.Address SpAddress
51 3 Admin.Phone SpPhone
By ResourceName i get what the value is for choosen language. So from admin page i want to see for by ResourceName what are ResourceValue for both languages.
So I need a resultset which returns something like this.
ResourceName ResourceValue As EnglishText ResourceValue As SpanishText
Admin.Address Address SpAddress
Admin.Phone Phone SpPhone

var loc1 = Context.ObjectSet<LocaleStringResource>.Where(r => r.LanguageId == 1);
var loc2 = Context.ObjectSet<LocaleStringResource>.Where(r => r.LanguageId == 2);
var result = (
from l1 in loc1
join l2 in loc2 on l1.ResourceName equals l2.ResourceName
select new{
ResourceName = l1.ResourceName,
EnglishText = l1.ResourceValue,
SpanishText = l2.ResourceValue
}
).ToList();

Entity framework doesn't support temporary tables and SELECT INTO construction so you cannot directly convert it. You must go through the logic of your application and change it so that it can be used with EF or you must wrap this code into stored procedure and call it from EF (btw. you will have to use column aliases for result set because column names must not be the same when used with EF).

Related

KQL :: return only tags with more than 4 records

I have created a Kusto query that allows me to return all our database park. The query only takes 10 lines of code:
Resources
| join kind=inner (
resourcecontainers
| where type == 'microsoft.resources/subscriptions'
| project subscriptionId, subscriptionName = name)
on subscriptionId
| where subscriptionName in~ ('Subscription1','Subscription2')
| where type =~ 'microsoft.sql/servers/databases'
| where name != 'master'
| project subscriptionName, resourceGroup, name, type, location,sku.tier, properties.requestedServiceObjectiveName, tags.customerCode
By contract we are supposed to give only 4 Azure SQL Database per customer but sometimes developers take a copy of them and they rename it _old or _backup and suddenly a customer can have 5 or 6 databases.
This increase the overall costs of the Cloud and I would like to have a list of all customers that have more than 4 databases.
In order to do so I can use the tag tags.customerCode which has the 3 letters identifier for each customer.
The code should work like this: if a customer is called ABC and there are 4 Azure SQL Databases with tags.customerCode ABC the query should return nothing. If there are 5 or 6 databases with tags.customerCode ABC the query should return all of them.
Not sure if Kusto can be that flexible.
Here is a possible solution.
It should be noted that Azure resource graph supports only a limited subset of KQL.
resourcecontainers
| where type == 'microsoft.resources/subscriptions'
//and name in~ ('Subscription1','Subscription2')
| project subscriptionId, subscriptionName = name
| join kind=inner
(
resources
| where type =~ 'microsoft.sql/servers/databases'
and name != 'master'
)
on subscriptionId
| project subscriptionId, subscriptionName, resourceGroup, name, type, location
,tier = sku.tier
,requestedServiceObjectiveName = properties.requestedServiceObjectiveName
,customerCode = tostring(tags.customerCode)
| summarize dbs = count(), details = make_list(pack_all()) by customerCode
| where dbs > 4
| mv-expand with_itemindex=db_seq ['details']
| project customerCode
,dbs
,db_seq = db_seq + 1
,subscriptionId = details.subscriptionId
,subscriptionName = details.subscriptionName
,resourceGroup = details.resourceGroup
,name = details.name
,type = details.type
,location = details.location
,tier = details.tier
,requestedServiceObjectiveName = details.requestedServiceObjectiveName

Use LIKE with multiple names from a different table in UPDATE

I'm looking to update a field to a different value if the string in name contains a value from a different table in PostgreSQL:
Table Types that needs to be updated
id | name | type
1 | Google Page | WEBSITE
2 | Yahoo Page | WEBSITE
3 | Facebook Page | WEBSITE
...
Table Companies that has the names
id | name
1 | Google
2 | Yahoo
3 | Facebook
4 | Twitter
5 | Stackoverflow
...
What I tried
UPDATE types
SET type = 'BUSINESS'
WHERE name LIKE CONCAT((SELECT companies.name from companies), '% Page')
But I'm getting this issue: [21000] ERROR: more than one row returned by a subquery used as an expression
You could use a subquery with exists logic to retain your current logic:
UPDATE types t
SET type = 'BUSINESS'
WHERE EXISTS (SELECT 1 FROM companies c
WHERE CONCAT(c.name, ' Page') = t.name);
You could also use an update join:
UPDATE types t
SET type = 'BUSINESS'
FROM companies c
WHERE t.name = CONCAT(c.name, ' Page');
You should use the IN directive:
WHERE name IN (SELECT CONCAT(companies.name, ' Page') name from companies)
Much cheaper than comparing concatenated strings:
UPDATE types t
SET type = 'BUSINESS'
FROM companies c
WHERE right(t.name, 5) = ' Page'
AND left(t.name, -5) = c.name;
db<>fiddle here

What is the equivalent of XML PATH and Stuff in Linq lambda expression (GROUP_CONCAT/STRING_AGG)?

I am having a table like this :
EmployeeId EmployeeName ItemName
4 Ganesh Key Board
4 Ganesh Processor
1 Jignesh Key Board
1 Jignesh Mouse
1 Jignesh Processor
3 Rakesh Key Board
2 Tejas Key Board
2 Tejas Mouse
2 Tejas Processor
I need to query this as if the itemname is different for the same employeeid and employeename we should have the items as ',' separated.
Like the one which is given below :
EmployeeId EmployeeName ItemName
1 Jignesh Key Board, Mouse, Processor
2 Tejas Key Board, Mouse, Processor
3 Rakesh Key Board
4 Ganesh Key Board, Processor
Here is the SQL Query for this:
Could anyone help me to convert the above SQL Query into Lambda Expression?
I'm assuming by Lambda expression you mean a Linq statement (e.g. to EF or Linq2Sql).
The FOR XML PATH and STUFF example shown was a hack to workaround the lack of GROUP_CONCAT or LISTAGG in Sql Server. Finally in Sql 2017 there is STRING_AGG
You don't need to reproduce the hack at all in LINQ - instead, simply load all rows for the set of employees of interest into memory, GroupBy the required key, and then use String.Join in a select projection:
var result = db.EmployeeItems
// If you have a filter add the .Where() here ...
.GroupBy(e => e.EmployeeId)
.ToList()
// Because the ToList(), this select projection is not done in the DB
.Select(eg => new
{
EmployeeId = eg.Key,
EmployeeName = eg.First().EmployeeName,
Items = string.Join(",", eg.Select(i => i.ItemName))
});
Where employeeItems is a projection of the join between Employee and Items:
var employeeItems = new []
{
new EmployeeItem{EmployeeId = 1, EmployeeName = "Ganesh", ItemName = "Keyboard"},
new EmployeeItem{EmployeeId = 1, EmployeeName = "Ganesh", ItemName = "Mouse"},
new EmployeeItem{EmployeeId = 2, EmployeeName = "John", ItemName = "Keyboard"}
};
Result:
1 Ganesh Keyboard,Mouse
2 John Keyboard

Filter SQL SELECT by XML node

There are single SQL Table with xml-type field:
| EntityId | EntityType | Xml column |
------------------------------------------------------
| 1 | Employee | `<productId>1</productId>`|
------------------------------------------------------
| 1 | Product | `<name>apple</name>` |
------------------------------------------------------
| 7 | Shop | `<country>...</country>` | |
-----------------------------------------------------|
What I need is a to filter table row by Xml node value:
SELECT * WHERE (EntityId='1' AND EntityType='Employee')
OR ( EntityId=SomeFuncToGetXmlFieldByNodeName('productId') )
Can u point me on how to write that SomeFuncToGetXmlFieldByNodeName(fieldName)
Looks like you want a function like this.
CREATE FUNCTION [dbo].[SomeFuncToGetXmlFieldByNodeName]
(
#NodeName nvarchar(100),
#XML xml
)
RETURNS nvarchar(max)
AS
BEGIN
RETURN #XML.value('(*[local-name(.) = sql:variable("#NodeName")]/text())[1]', 'nvarchar(max)')
END
It takes a node name and a some XML as parameter and returns the value in the node.
Use the function like this:
select T.EntityId,
T.EntityType,
T.[Xml column]
from YourTable as T
where T.EntityID = 1 and
T.EntityType = 'Employee' or
T.EntityId = dbo.SomeFuncToGetXmlFieldByNodeName('productId', T.[Xml column])
Instead of using the above I want to recommend you to try a query that does not use the scalar valued function. It uses exist() Method (xml Data Type) instead.
select T.EntityId,
T.EntityType,
T.[Xml column]
from YourTable as T
where T.EntityID = 1 and
T.EntityType = 'Employee' or
T.[Xml column].exist('/productId[. = sql:column("T.EntityID")]') = 1
I think you're looking for the documentation!
The "query" method is likely what you'll need. See examples in the linked article.

Linq to Entities Select Distinct

I'm not sure what I'm missing but I've been thrashing at this one all afternoon.
I have a Sql Server view of Companies which looks like this:
CompanyId varchar(30) NOT NULL
CompanyName varchar(100) NOT NULL
CompanyPriority int NULL
ConfigItem int NOT NULL
With data that looks a bit like this:
00001 | Company One | 99 | 123
00001 | Company One | 99 | 456
00001 | Company One | 99 | 789
00002 | Company Two | 99 | 123
00002 | Company Two | 99 | 456
I'm trying to get a distinct list of companies. The sql query I want to exectute is
select distinct CompanyId, CompanyName,CompanyPriority from vwCompany
which gives me exactly the results I want which would be
00001 | Company One | 99
00002 | Company Two | 99
But for the life of me I can't find the LINQ query that results in this sql, or anything that produces the same results.
All of the questions I've found use grouping which works fine in my unit tests but fails to return distinct results when executed against an actual database.
EDIT:
So I've tried a few things based on the answers so far.
Dim data = _miRepository.GetCompanies().
Select(Function(c) New With {
.companyId = c.CompanyId,
.companyName = c.CompanyName,
.companyPriority = c.CompanyPriority
}
).Distinct().ToList()
generates the sql
SELECT
1 AS [C1],
[Extent1].[CompanyId] AS [CompanyId],
[Extent1].[CompanyName] AS [CompanyName],
[Extent1].[CompanyPriority] AS [CompanyPriority]
FROM (SELECT
[vwCompany].[CompanyId] AS [CompanyId],
[vwCompany].[CompanyName] AS [CompanyName],
[vwCompany].[CompanyPriority] AS [CompanyPriority],
[vwCompany].[CiId] AS [CiId]
FROM [dbo].[vwCompany] AS [vwCompany]) AS [Extent1]
which doesn't have the distinct operator in it at all :(
And yes, I'm doing this in VB.NET just to make it harder to find good examples :\
EDIT 2:
I'm trying to get as close to Eric Js answer as I can in VB.
Dim data = (From c In _miRepository.GetCompanies()
Select New With {.companyId = c.CompanyId,
.companyName = c.CompanyName,
.companyPriority = c.CompanyPriority
}
).Distinct().ToList()
gives me
SELECT
1 AS [C1],
[Extent1].[CompanyId] AS [CompanyId],
[Extent1].[CompanyName] AS [CompanyName],
[Extent1].[CompanyPriority] AS [CompanyPriority]
FROM (SELECT
[vwCompany].[CompanyId] AS [CompanyId],
[vwCompany].[CompanyName] AS [CompanyName],
[vwCompany].[CompanyPriority] AS [CompanyPriority],
[vwCompany].[CiId] AS [CiId]
FROM [dbo].[vwCompany] AS [vwCompany]) AS [Extent1]
Still no distinct keyword to be found :(
Maybe there's a subtle difference in VB.NET that I'm missing.
EDIT 3:
In order to progress with the rest of this application I've given up for the moment and created a new view (vwDistinctCompanies) using the sql statement at the start of the question.
If anyone manages to get this working in VB.NET against a Sql view please let me know. Quite why this should be so difficult in LINQ I have no idea :(
Try using .Distinct() at the end of your query, e.g.
(from r in ctx.MyTable where SomeCondition select r).Distinct();
http://msdn.microsoft.com/en-us/library/system.linq.enumerable.distinct.aspx
If needed, you can also provide an IEqualityComparer. However, to use the IEqualityComparer, the resulting enumerable must first be materialized using .ToEnumerable(). Doing this means the Distinct() operation is performed on the client rather than on the DB server.
http://msdn.microsoft.com/en-us/library/bb338049.aspx
The IEqualityComparer allows you to control exactly which records are treated as equal and therefore not distinct from other records.
If you want to select only a subset of columns of your table, change
select r
to select either an anonymous type like this:
(from r in ctx.MyTable where SomeCondition
select new
{
CompanyId = r.CompanyId,
CompanyName = r.CompanyName,
CompanyPriority = r.CompanyPriority
}
).Distinct();
or if you need a strongly typed object (for example, because you are using strongly typed views in MVC:
public class CompanyModel
{
public int CompanyId { get; set; }
public string CompanyName { get; set; }
public int CompanyPriority { get; set; }
}
// Then in the Linq statement
(from r in ctx.MyTable where SomeCondition
select new CompanyModel()
{
CompanyId = r.CompanyId,
CompanyName = r.CompanyName,
CompanyPriority = r.CompanyPriority
}
).Distinct();
-EDITED:-
Ignore all my code that I mentioned earlier (everything after the end edit section). I tried further test. Plug the following VB code and tell me what results you got:
(From c In ctx.Companies Select New With { _
Key .companyId = c.CompanyId, _
Key .companyName = c.CompanyName, _
Key .companyPriority = c.CompanyPriority _
}).Distinct()
I tested them using LINQPad and I got the following SQL:
SELECT DISTINCT [t0].[CompanyId] AS [companyId],
[t0].[CompanyName] AS [companyName],
[t0].[CompanyPriority] AS [companyPriority]
FROM [Companies] AS [t0]
-END EDIT-
I had this problem few days ago. This is what I ended up doing.
What you are looking for would require the GroupBy clause as you mentioned in your post. Just using Distinct will not work as how you would expect (As far as I know). The following lambda expression is what I did and right after is the SQL statement that is generated through the lambda code.
Lambda Code:
Companies.GroupBy(c => new {
c.CompanyId,
c.CompanyName,
c.CompanyPriority
})
.Select(p => new {
CompanyId = p.Key.CompanyId,
CompanyName = p.Key.CompanyName,
CompanyPriority = p.Key.CompanyPriority
})
SQL Code:
SELECT [t0].[CompanyId] AS [companyId],
[t0].[CompanyName] AS [companyName],
[t0].[CompanyPriority] AS [companyPriority]
FROM [Companies] AS [t0]
GROUP BY [t0].[CompanyId],
[t0].[CompanyName],
[t0].[CompanyPriority]
Try:
var results = (from company in context.Companies
select new {
CompanyId = company.CompanyId,
CompanyName = company.CompanyName,
CompanyPriority = company.CompanyPriority
}).Distinct();
The key is to get the pieces of the query that CAN be unique together, then call the .Distinct() extension. If you leave the configID property in there, they will all be unique.
var query = from c in context.vwCompany
group c by new {
c.CompanyId,
c.CompanyName,
c.CompanyPriority } into g
select g.Key;
Generated query (from SQL Server Profiler) will look like:
SELECT
1 AS [C1],
[Distinct1].[CompanyId] AS [CompanyId],
[Distinct1].[CompanyName] AS [CompanyName]
[Distinct1].[CompanyPriority] AS [CompanyPriority]
FROM ( SELECT DISTINCT
[Extent1].[CompanyId] AS [CompanyId],
[Extent1].[CompanyName] AS [CompanyName]
[Extent1].[CompanyPriority] AS [CompanyPriority]
FROM [dbo].[vwCompany] AS [Extent1]
) AS [Distinct1]
Shouldn't that be two tables? One with
00001 | Company One | 99
00002 | Company Two | 99
And the other with
00001 | 123
00001 | 456
00001 | 789
00002 | 123
00002 | 456
which is more normalized and would make your query really easy?