I have a working SQL query as shown below. I want to create an equivalent Linq query. Not have much success.
select u.Id as userId, u.CustomerId, a.Id as appId, a.Created as appCreated
from EO_AppUsers u
left join EO_Policies p on (u.Id = p.AppUser_Id)
CROSS APPLY (
select TOP 1 id, created, AppUser_Id
from EO_Applications d
WHERE d.AppUser_id = u.id
order by Created desc ) a
CREATE TABLE [dbo].[EO_AppUsers] (
[Id] NVARCHAR (128) NOT NULL
CREATE TABLE [dbo].[EO_Policies] (
[Id] NVARCHAR (128) NOT NULL,
[AppUser_Id] NVARCHAR (128) NULL,
CREATE TABLE [dbo].[EO_Applications] (
[Id] NVARCHAR (128) NOT NULL,
[Created] DATETIME2 (7) NOT NULL,
[AppUser_Id] NVARCHAR (128) NULL,
EO_AppUsers has a EO_Policies and zero or more EO_Applications.
The SQL creates a report of all EO_AppUsers and associated EO_Policies and the latest/newest EO_Applications
The following handles returning EO_AppUsers and EO_Policies but is missing the EO_Applications. It needs the CROSS APPLY from the SQL query above.
var q = (from u in dbContext.EO_AppUsers
join p in dbContext.EO_Policies on u.Id equals p.AppUser.Id
//join a in dbContext.EO_Applications on u.Id equals a.AppUser.Id
select new
{
/// return fields from EO_AppUsers, EO_Policies and EO_Applications
});
You can try this linq query.
from u in EO_AppUsers
join p in EO_Policies on u.Id equals p.AppUser_Id into pl
from lp in pl.DefaultIfEmpty()
from a in EO_Applications.Where(d => d.AppUser_Id == u.Id)
.OrderByDescending(d => d.Created)
.Take(1)
.DefaultIfEmpty()
select new { userId = u.Id,
u.CustomerId,
appId = a.Id,
appCreated = a.Created,
polId = lp.Id
}
Related
I have to tables: Register and Price.
CREATE TABLE [dbo].[Register](
[RegisterID] [int] NULL,
[GroupID] [int] NULL,
[TestID] [int] NULL)
CREATE TABLE [dbo].[Price](
[ID] [int] NULL,
[GroupID] [int] NULL,
[Price] [bigint] NULL,
[Status] [bit] NULL)
Assuming information similar to the image above, consider the following query
SELECT Price.*
FROM Register RIGHT OUTER JOIN Price ON Register.GroupID = Price.GroupID
WHERE (Price.Status = 1) AND (Register.TestID = 50)
The output will be displayed as shown below.
My expectation is that the first and second rows of the price table will be displayed. So where is my mistake and how should I change the query to get the right output?
The restriction on the Register table which currently appears in the WHERE clause would have to be moved to the ON clause to get the behavior you want:
SELECT p.*
FROM Register r
RIGHT JOIN Price p ON r.GroupID = p.GroupID AND r.TestID = 50;
WHERE p.Status = 1
Note that more typically you would express the above via a left join:
SELECT p.*
FROM Price p
LEFT JOIN Register r ON r.GroupID = p.GroupID AND r.TestID = 50
WHERE p.Status = 1;
This is my query
SELECT p.book FROM customers_books p
INNER JOIN books b ON p.book = b.id
INNER JOIN bookprices bp ON bp.book = p.book
WHERE b.status = 'PUBLISHED' AND bp.currency_code = 'GBP'
AND p.book NOT IN (SELECT cb.book FROM customers_books cb WHERE cb.customer = 1)
GROUP BY p.book, p.created_date ORDER BY p.created_date DESC
This is the data in my customers_books table,
I expect only 8,6,1 of books IDs to return but query is returning 8,6,1,1
table structures are here
CREATE TABLE "public"."customers_books" (
"id" int8 NOT NULL,
"created_date" timestamp(6),
"book" int8,
"customer" int8,
);
CREATE TABLE "public"."books" (
"id" int8 NOT NULL,
"created_date" timestamp(6),
"status" varchar(255) COLLATE "pg_catalog"."default",
)
CREATE TABLE "public"."bookprices" (
"id" int8 NOT NULL,
"currency_code" varchar(255) COLLATE "pg_catalog"."default",
"book" int8
)
what do you think I am doing wrong here.
I really dont want to use p.created_date in group by but I was forced to use because of order by
You have too many joins in the outer query:
SELECT b.book
FROM books b INNER JOIN
bookprices bp
ON bp.book = p.book
WHERE b.status = 'PUBLISHED' AND bp.currency_code = 'GBP' AND
NOT EXISTS (SELECT 1
FROM customers_books cb
WHERE cb.book = p.book AND cb.customer = 1
) ;
Note that I replaced the NOT IN with NOT EXISTS. I strongly, strongly discourage you from using NOT IN with a subquery. If the subquery returns any NULL values, then NOT IN returns no rows at all. It is better to sidestep this issue just by using NOT EXISTS.
I have a query in MSSQL 2008 like:
IF OBJECT_Id('tempdb..#AccessibleFacilities') IS NOT NULL DROP TABLE #AccessibleFacilities
SELECT u.Userid
, AccesibleFacilityIds = dbo.GetCommaDelimitedString(upf.Facility_Id)
INTO #AccessibleFacilities
FROM Users u
INNER join UserProfileFacilities upf on upf.UserProfile_Id = up.Id
WHERE LOWER(u.Userid) = LOWER(#userId)
GROUP BY u.Userid
This query returns AccessibleFacilityIds like ",1,2,3,4,5,6,". Please note that I am not able to modify GetCommaDelimitedString function.
What I actually need to do is that using those facility ids to reach provs like below:
INSERT INTO #AccessibleProvs
SELECT Userid = #userId
, AccessibleProvIds = dbo.GetCommaDelimitedString(distinct p.Id)
FROM Provs p
inner join ProvFacs pf on p.Id = pf.Provider_Id
WHERE pf.Facility_Id in
(select a.AccesibleFacilityIds from #AccessibleFacilities a)
However, it gives me an error like:
Conversion failed when converting the nvarchar value ',1,2,3,4,5,6,'
to data type int.
I tried removing the comma signs at the start and end like below to fix it, but it did not help:
...
where pf.Facility_Id in (
select SUBSTRING(a.AccesibleFacilityIds,2,LEN(a.AccesibleFacilityIds)-2)
from #AccessibleFacilities a
)
Any advice would be appreciated. Thanks.
Instead of converting Facility_Id into a comma delimited string, why not keep it as a usable column in your temp table?
if object_Id('tempdb..#AccessibleFacilities') is not null drop table #AccessibleFacilities;
select
u.UserId
, upf.Facility_Id
into #AccessibleFacilities
from Users u
inner join UserProfileFacilities upf
on upf.UserProfile_Id = up.Id
Then use it as you did with in() or with exists():
insert into #AccessibleProvs
select
UserId = #userId
, AccessibleProvIds = dbo.GetCommaDelimitedString(distinct p.Id)
from Provs p
inner join ProvFacs pf
on p.Id = pf.Provider_Id
where exists (
select 1
from #AccessibleFacilities a
where a.Facility_Id = pf.Facility_Id
--and a.UserId = #UserId -- Do you need to check Facility_Id by User?
)
If you have the value for #UserId in the beginning, you could limit your temp table usage to just the user you need. Hopefully this code is not meant for use in some sort of cursor or other loop.
My database table are as follow
CREATE TABLE [dbo].[vProduct](
[nId] [int] NOT NULL, //Primary key
[sName] [varchar](255) NULL
)
CREATE TABLE [dbo].[vProductLanguage](
[kProduct] [int] NOT NULL,
[kLanguage] [int] NOT NULL //Foriegn key to table vLanguage
)
CREATE TABLE [dbo].[vLanguage](
[nId] [int] NOT NULL, //Primary key
[sName] [varchar](50) NULL,
[language] [char](2) NULL
)
Table vProduct has relation to vProductLanguage on vProduct.nId = vProductLanguage.kLanguage
Table vProductLanguage has relation to vLanguage on vProductLanguage.kLanguage = vLanguage.nid
So its like table vProductLanguage will have languages which are being selected
Rows will be like image below
Table vProduct
Table vProductLanguage
Table vLanguage
What i want is select all Languages from table vLanguage and selected languages from table vProductLanguage. This will be associated with table vProduct.
I tried below query but it only returns me the languages which are associated with product.
select * from
vProductLanguage
left join vLanguage on vProductLanguage.kLanguage = vLanguage.nId
left join vProduct on vProductLanguage.kProduct = vProduct.nId
Where vProduct.nId = 1
I want to select all the rows from table vLanguage and table vProductLanguage.
Hope i made my question clear.
It sounds like you want to start your JOIN with the vLanguage table first:
select *
from vLanguage l
left join vProductLanguage pl
on l.nid = pl.kLanguage
left join vProduct p
on pl.kProduct = p.nid
and p.nid = 1
See SQL Fiddle with Demo.
This will return all rows from the vLanguage table and any matching rows from the vProductLanguage table. .
If you have more than one vProduct then you can rewrite the query slightly to:
select *
from vLanguage l
left join
(
select pl.kLanguage,
p.nid,
p.sName
from vProductLanguage pl
left join vProduct p
on pl.kProduct = p.nid
where p.nid = 1
) p
on l.nid = p.kLanguage
See SQL Fiddle with Demo
I wrote the code for a View which needs to call a user defined function which returns a table to join with it. The problem here is passing the parameter that this functions needs straight out of my view.
Below is the code of my view:
select
GG.Gid,
GG.StockType StockType,
COALESCE(STC.Contract, 0) ContractId,
COALESCE(C.[$Refex], null) ContractRefex,
ST.[$Refex] StockTypeRefex
from
(
select
G.Gid,
coalesce(max(G.GEStockType), max(G.EAStockType)) StockType--,
--case when coalesce(G.GEStockType, G.EAStockType) is null then null else coalesce(G.GEStartDate, G.EAStartDate) end StartDate
from
(
select
G.Gid, SI.StockType EAStockType, SI.[Date] EAStartDate, null GEStockType, null GEStartDate
from Goods G
inner join SiteIn SI on G.SiteIn=SI.[$Id]
union
select G.Gid, null EAStockType, null EAStartDate, GE.StockType, GE.EventOn
from
(
Select
GE.Gid, max(GE.EventOn) GEStartDate
from GoodsEvent GE
where GE.IsDeleted=0 and GE.[Type]='ST' and GE.EventOn < GETDATE()
group by Gid
) G
inner join GoodsEvent GE on GE.Gid=G.Gid
and G.GEStartDate=GE.EventOn
and GE.[Type]='ST'
) G
group by G.Gid
) GG
left outer join StockType ST on ST.[$Id]=GG.StockType
inner join (SELECT * FROM [dbo].StockTypeContractGetClosestStartDate(ST.[$Id]))
STC on GG.StockType = STC.[Parent]
inner join Contract C On STC.Contract = C.[$Id]
And this is the code of my function:
CREATE FUNCTION StockTypeContractGetClosestStartDate
(
#ParentId int
)
RETURNS #StockTypeContract TABLE
(
[StartDate] [DateTime] null,
[Parent] [int] not null,
[Contract] [int] null
)
AS
BEGIN
INSERT #StockTypeContract
SELECT TOP 1 STC.StartDate , STC.[$ParentId] , STC.Contract
from StockTypeContract STC
where STC.[$ParentId] = #ParentId AND STC.StartDate <= GETDATE()
order by STC.StartDate desc
RETURN
END
It gives me an error when trying to pass ST.[$Id] to my function, the error is "The multi-part identifier ST.$Id could not be bound".
Is there any work-around for this?
You actually needs CROSS or OUTER APPLY. And from SO too
....
left outer join StockType ST on ST.[$Id]=GG.StockType
CROSS APPLY
[dbo].StockTypeContractGetClosestStartDate(ST.[$Id])
...
(I've simplified parenthesis here BTW, probably wrongly)
Your problem is "get a resultset from StockTypeContractGetClosestStartDate per ST.[$Id]
If I am correct your only inserting one record in the return table of your function, if that is the case then you can rebuild the function as a scalar function, this returns only one value and should solve the multi-part problem.
At the moment your trying to join with a possible "multi valued id".
see http://technet.microsoft.com/en-us/library/ms186755.aspx for the scalar function