How to supply multiple values in between clause after where clause - sql-server

SELECT
ROW_NUMBER() OVER (ORDER BY Vendor_PrimaryInfo.Vendor_ID ASC) AS RowNumber,
*
FROM
Unit_Table
INNER JOIN
Vendor_Base_Price ON Unit_Table.Unit_ID = Vendor_Base_Price.Unit_ID
INNER JOIN
Vendor_PrimaryInfo ON Vendor_Base_Price.Vendor_ID = Vendor_PrimaryInfo.Vendor_ID
INNER JOIN
Vendor_Registration ON Vendor_Base_Price.Vendor_ID = Vendor_Registration.Vendor_ID
AND Vendor_PrimaryInfo.Vendor_ID = Vendor_Registration.Vendor_ID
INNER JOIN
Category_Table ON Vendor_Registration.Category_ID = Category_Table.Category_ID
LEFT JOIN
Vendor_Value_Table ON Vendor_Registration.Vendor_ID = Vendor_Value_Table.Vendor_ID
LEFT JOIN
Feature_Table ON Vendor_Value_Table.Feature_ID = Feature_Table.Feature_ID
WHERE
Vendor_Registration.Category_ID = 5
AND Vendor_PrimaryInfo.City = 'City'
AND (value_text in ('sample value') or
(SELECT
CASE WHEN ISNUMERIC(value_text) = 1
THEN CAST(value_text AS INT)
ELSE -1
END) BETWEEN 0 AND 100)
As column has multiple values which may be text or may be int that's why I cast based on case. My question is: I just want to fetch the records either whose value is between 0 and 100 or value between 300 to 400 or value is like sample value.
I just want to place the condition after where clause and do not want to use column_name multiple time in between operator because these values are coming from url
Thanks in advance any help would be grateful.

You can try this way..
WHERE
Vendor_Registration.Category_ID = 5
AND Vendor_PrimaryInfo.City = 'City'
AND (value_text in ('sample value') or
(CASE WHEN (ISNUMERIC(value_text) = 1)
THEN CAST(value_text AS INT)
ELSE -1
END) BETWEEN 0 AND 100)

Related

EF LINQ Count by Grouped field

I have the following data schema:
With the following LINQ query:
var profiles = (
from p in context.BusinessProfiles
join u in context.Users on p.UserId equals u.Id
join addr in context.BusinessAddress on p.ProfileId equals addr.ProfileId into addrj
from addr in addrj.DefaultIfEmpty()
join pa in context.BusinessProfileActivities on p.ProfileId equals pa.ProfileId into paj
from paIfNull in paj.DefaultIfEmpty()
where p.ProfileId >= 137 && p.ProfileId <= 139
group new { p, u, addr, paIfNull }
by new {
p.ProfileId,
p.CompanyName,
p.Email,
UserEmail = u.Email,
addr.City, addr.Region,
addr.Country,
ActivityProfileId = paIfNull.ProfileId }
into pg
select new {
pg.Key.ProfileId,
pg.Key.CompanyName,
Email = pg.Key.Email ?? pg.Key.UserEmail,
pg.Key.City,
pg.Key.Region,
pg.Key.Country,
MatchingActivities = pg.Key.ActivityProfileId > 0 ? pg.Count() : 0
} into result
orderby result.MatchingActivities descending
select result
);
Which results with:
This result is corrent (ProfileId 137 has 0 activities, 138 has 1 and 139 has 2), but it produces the following SQL:
SELECT [b].[ProfileId], [b].[CompanyName], COALESCE([b].[Email], [a].[Email]) AS [Email], [b0].[City], [b0].[Region], [b0].[Country],
CASE WHEN [b1].[ProfileId] > CAST(0 AS bigint) THEN COUNT(*)
ELSE 0
END AS [MatchingActivities]
FROM [BusinessProfiles] AS [b]
INNER JOIN [AspNetUsers] AS [a] ON [b].[UserId] = [a].[Id]
LEFT JOIN [BusinessAddress] AS [b0] ON [b].[ProfileId] = [b0].[ProfileId]
LEFT JOIN [BusinessProfileActivities] AS [b1] ON [b].[ProfileId] = [b1].[ProfileId]
WHERE ([b].[ProfileId] >= CAST(137 AS bigint)) AND ([b].[ProfileId] <= CAST(139 AS bigint))
GROUP BY [b].[ProfileId], [b].[CompanyName], [b].[Email], [a].[Email], [b0].[City], [b0].[Region], [b0].[Country], [b1].[ProfileId]
ORDER BY CASE
WHEN [b1].[ProfileId] > CAST(0 AS bigint) THEN COUNT(*)
ELSE 0
END DESC
In SQL, I can avoid both CASE WHEN if I use COUNT([b1].[ProfileId]) like this:
SELECT [b].[ProfileId], [b].[CompanyName], COALESCE([b].[Email], [a].[Email]) AS [Email], [b0].[City], [b0].[Region], [b0].[Country],
COUNT([b1].[ProfileId]) AS [MatchingActivities]
FROM [BusinessProfiles] AS [b]
INNER JOIN [AspNetUsers] AS [a] ON [b].[UserId] = [a].[Id]
LEFT JOIN [BusinessAddress] AS [b0] ON [b].[ProfileId] = [b0].[ProfileId]
LEFT JOIN [BusinessProfileActivities] AS [b1] ON [b].[ProfileId] = [b1].[ProfileId]
WHERE ([b].[ProfileId] >= CAST(137 AS bigint)) AND ([b].[ProfileId] <= CAST(139 AS bigint))
GROUP BY [b].[ProfileId], [b].[CompanyName], [b].[Email], [a].[Email], [b0].[City], [b0].[Region], [b0].[Country], [b1].[ProfileId]
ORDER BY [MatchingActivities] DESC
My question is, how can I count by grouped ActivityProfileId = paIfNull.ProfileId using LINQ and get EF to generate the above SQL?
I have tried so many variations resulting mostly in EF to SQL errors.
MatchingActivities = pg.Count(t => t.ActivityProfileId!= 0)
MatchingActivities = pg.Select(t => t.paIfNull.ProfileId).Distinct().Count(),
MatchingActivities = pg.Count(t => t.paIfNull != null),
All result in errors like System.InvalidOperationException: The LINQ expression ... could not be translated. or getting MatchingActivities as 1 instead of 0.
Related Q/A:
LINQ Count returning 1 instead of zero for an empty group
Group by in LINQ
How to write left join, group by and average in c# entity framework Linq
In short you can't! EF Core still doesn't support that.
See this:
https://github.com/dotnet/efcore/issues/17376
And also See:
https://stackoverflow.com/a/61878332/9212040

Avoid table function in where clause?

I have added table function in the where clause.
select cmp_id, acno_code, sl_type, sl_code, 0 op_Dr, 0 op_cr, 0 tr_Dr, sum(amount) tr_Cr
from vf_finance
where cmp_id =#cmp_id1
and unitcode in (select * from UTILfn_Split( #unit_code,',') )
and stat_code in ('AT','PR' )
--and pc_code in (select * from UTILfn_Split( #sba,',') )
AND DOC_dT >=convert(datetime,#from_date,103) and doc_Dt <= convert(datetime,#to_date,103)
and amount < 0
GROUP BY cmp_id, acno_code, sl_type, sl_code
) as gl
inner join ps_Accmas acc on acc.cmp_id = gl.cmp_id and acc.acno_Code = gl.acno_code
inner join ps_owner o on gl.cmp_id = o.cmp_id
left outer join view_sl_code sl on gl.cmp_id = sl.cmp_id and gl.sl_type = sl.sl_type and gl.sl_Code = sl.sl_Code
inner join ps_slType slt on gl.cmp_id = slt.cmp_id and gl.sl_Type = slt.sl_type
where sl.sl_type in (select * from UTILfn_Split( #sl_type,',') )
and acc.acno_code in(select * from UTILfn_Split( #facno_code,',') )
group by gl.cmp_id, gl.acno_code,gl.sl_code,gl.sl_type,slt.sl_DEsc,acc.acno_DEsc, sl.sl_DEsc, o.owner_name
order by gl.cmp_id, gl.acno_code,gl.sl_code,gl.sl_type
Can anyone please suggest how I can avoid function in where clause?
You may try this. There are some issues in this existing query which I'll point first
First unitcode in (select * from UTILfn_Split( #unit_code,',') here you must use one column name instead of *, although i don't know about your function UTILfn_Split but still mention column name is preferable.
for your query you may use inner join instead of in with function having return type table.
Instead of
sl.sl_type in (select * from UTILfn_Split( #sl_type,',') )
You may try this
yourtble as sl inner join
(select value from UTILfn_Split( #sl_type,',') as t2
on sl.sl_type = t2.[value] ---- here column name with t2 depends on your function,
---what table structure is returning, in your case it is [value]

Aggregate function is return incorrect value when joining more table

I am getting the Total sale using the following query.
SELECT SUM([B].[TotalSale])
FROM [dbo].[BookingDetail] [BF] WITH (READPAST)
INNER JOIN [dbo].[Booking] [B] WITH (READPAST) ON [B].[BookingDetailID] = [BF].[ID]
WHERE [BF].[MarketID] = '2'
I want to add another column to get the Gross Sale .
For that I have to make a join with another table called AirTraveler.
But once I add a new table to the query
SELECT
SUM([B].[TotalSale]) ,
SUM(CASE WHEN [B].[TravelSectorID] = 3 AND [B].[BookingStatusID] IN (16, 20, 22, 23) THEN COALESCE([B].[TotalSale], 0.0)
WHEN ([B].[TravelSectorID] = 1 AND [B].[IsDomestic] = 1 AND CONVERT(varchar, [AT].[FareDetails].query('string(/AirFareInfo[1]/PT[1])')) = 'FlightAndHotel') THEN [AT].[TotalSale]
ELSE 0 END) AS [GrossSale]
FROM [dbo].[BookingDetail] [BF] WITH (READPAST)
INNER JOIN [dbo].[Booking] [B] WITH (READPAST) ON [B].[BookingDetailID] = [BF].[ID]
LEFT OUTER JOIN [dbo].[AirTraveler] [AT] WITH(READPAST) ON [B].[ID] = [AT].[BookingID]
WHERE [BF].[MarketID] = '2'
it is giving incorrect result of [TotalSale] .the aggregate functions return wrong values because there may be multiple AirTraveler per Booking ID, which is correct. What can I do to solve the aggregate function problem?
I am actually stuck.
I am using SQL Server .
Thanks in advance.
Not tested or anything, but when you are joining to a lower level table that causes a header table to double count, you can pre-aggregate it before it joins
This is probably missing some opening/closing brackets and aliases but hopefully you can work it out
SELECT
SUM([B].[TotalSale]) ,
SUM(CASE WHEN [B].[TravelSectorID] = 3
AND [B].[BookingStatusID] IN (16, 20, 22, 23)
THEN COALESCE([B].[TotalSale], 0.0)
WHEN ([B].[TravelSectorID] = 1 AND [B].[IsDomestic] = 1
THEN [AT].[TotalSale]
ELSE 0 END) AS [GrossSale]
FROM [dbo].[BookingDetail] [BF] WITH (READPAST)
INNER JOIN [dbo].[Booking] [B] WITH (READPAST) ON [B].[BookingDetailID] = [BF].[ID]
LEFT OUTER JOIN
(
SELECT BookingID, SUM(CASE WHEN
CONVERT(varchar(50), [FareDetails].query('string(/AirFareInfo[1]/PT[1])'))
= 'FlightAndHotel') THEN [TotalSale] ELSE 0 END) TotalSale
FROM [dbo].[AirTraveler] [AT] WITH(READPAST)
GROUP BY BookingID
) AT
ON [B].[ID] = [AT].[BookingID]
WHERE [BF].[MarketID] = '2'
Also I gave your varchar cast a size - I think if you don't do this it'll be 1 so your case is never true

Sub query in Store Procedure

I have a query in sql stored procedure. I want to get record from other query from its id how I do that.
SELECT t.Name ,t.CreatedDate ,t.CreatedBy , t.Amount
,t.Margin ,t.Probability ,t.Id
FROM (SELECT a = 1) a
CROSS JOIN
(SELECT
Name = HirschInternational_MSCRM.dbo.SalesOrderBase.Name
,CreatedDate=HirschInternational_MSCRM.dbo.SalesOrderBase.CreatedOn
,CreatedBy=HirschInternational_MSCRM.dbo.SystemUserBase.FullName
,Amount = totalamount
,Probability=CloseProbability
,Id=SalesOrderId
,Margin=(SELECT ( ISNULL( ((Sum(Price)-Sum(CurrentCost)) / NULLIF( Sum(Price), 0 ))*100, 0 ) )
FROM HirschInternational_MSCRM.dbo.ProductBase
JOIN HirschInternational_MSCRM.dbo.SalesOrderDetailBase
ON HirschInternational_MSCRM.dbo.SalesOrderDetailBase.ProductId = HirschInternational_MSCRM.dbo.ProductBase.ProductId
JOIN HirschInternational_MSCRM.dbo.SalesOrderBase
ON HirschInternational_MSCRM.dbo.SalesOrderBase.SalesOrderId = HirschInternational_MSCRM.dbo.SalesOrderDetailBase.SalesOrderId)
FROM HirschInternational_MSCRM.dbo.SalesOrderBase
JOIN HirschInternational_MSCRM.dbo.OpportunityBase
ON HirschInternational_MSCRM.dbo.SalesOrderBase.Opportunityid = HirschInternational_MSCRM.dbo.OpportunityBase.Opportunityid
JOIN HirschInternational_MSCRM.dbo.SystemUserBase
ON HirschInternational_MSCRM.dbo.SystemUserBase.SystemUserId = HirschInternational_MSCRM.dbo.SalesOrderBase.CreatedBy
WHERE YEAR(HirschInternational_MSCRM.dbo.SalesOrderBase.CreatedOn)=YEAR(GETDATE())
I want Margin from every record I want Output like
It's not entirely clear what you want, but you might be looking for something like
select *
from (your SQL SELECT statement goes here) t1
where id = ?;
I want to get margin of every record how I filter margin query for SalesOrderId
like
Margin=(SELECT ( ISNULL( ((Sum(Price)-Sum(CurrentCost)) / NULLIF( Sum(Price), 0 ))*100, 0 ) )
FROM HirschInternational_MSCRM.dbo.ProductBase
JOIN HirschInternational_MSCRM.dbo.SalesOrderDetailBase
ON HirschInternational_MSCRM.dbo.SalesOrderDetailBase.ProductId = HirschInternational_MSCRM.dbo.ProductBase.ProductId
JOIN HirschInternational_MSCRM.dbo.SalesOrderBase
ON HirschInternational_MSCRM.dbo.SalesOrderBase.SalesOrderId = HirschInternational_MSCRM.dbo.SalesOrderDetailBase.SalesOrderId
Where HirschInternational_MSCRM.dbo.SalesOrderBase.SalesOrderId= //SalesOrderId that I get in main query)
how I pass that SalesOrderId in this query

paging over SELECT UNION super slow and killing my server

I have an SP that returns paged data from a query that contains a UNION. This is killing my DB and taking 30 seconds to run sometimes, am I missing something obvious here? What can I do to improve it's performance?
Tables Involved: Products, Categories, CategoryProducts
Goal:
Any Products that are not in a Category or have been deleted from a category UNION all Products currently in a category and page over them for a web service.
I have Indexes on all columns that I am joining on and there are 427,996 Products, 6148 Categories and 409,691 CategoryProducts in the database.
Here is my query that is taking between 6, and 30 seconds to run:
SELECT * FROM (
SELECT ROW_NUMBER() OVER(ORDER BY Products.ItemID, Products.ManufacturerID) AS RowNum, *
FROM
(
SELECT Products.*,
CategoryID = NULL, CategoryName = NULL,
CategoryProductID = NULL,
ContainerMinimumQuantity =
CASE COALESCE(Products.ContainerMinQty, 0)
WHEN 0 THEN Products.OrderMinimumQuantity
ELSE Products.ContainerMinQty
END
Products.IsDeleted,
SortOrder = NULL
FROM CategoryProducts RIGHT OUTER JOIN Products
ON CategoryProducts.ManufacturerID = Products.ManufacturerID
AND CategoryProducts.ItemID = Products.ItemID
WHERE (Products.ManufacturerID = #ManufacturerID)
AND (Products.ModifiedOn > #tStamp )
AND ((CategoryProducts.IsDeleted = 1) OR (CategoryProducts.IsDeleted IS NULL))
UNION
SELECT Products.*,
CategoryProducts.CategoryID , CategoryProducts.CategoryName,
CategoryProducts.CategoryProductID ,
ContainerMinimumQuantity =
CASE COALESCE(Products.ContainerMinQty, 0)
WHEN 0 THEN Products.OrderMinimumQuantity
ELSE Products.ContainerMinQty
END
CategoryProducts.IsDeleted,
CategoryProducts.SortOrder
FROM Categories INNER JOIN
CategoryProducts ON Categories.CategoryID = CategoryProducts.CategoryID INNER JOIN
Products ON CategoryProducts.ManufacturerID = Products.ManufacturerID
AND CategoryProducts.ItemID = Products.ItemID
WHERE (Products.ManufacturerID = #ManufacturerID)
AND (Products.ModifiedOn > #tStamp OR CategoryProducts.ModifiedOn > #tStamp))
AS Products) AS C
WHERE RowNum >= #StartRow AND RowNum <= #EndRow
Any insight would be greatly appreciated.
If I read your situation correctly, the only reason for having two distinct queries is treatment of missing/deleted CategoryProducts. I tried to address this issue by left join with IsDeleted = 0 to bring all deleted CategoryProducts to nulls, so I don't have to test them again. ModifiedOn part got another test for null for missing/deleted Categoryproducts you wish to retrieve.
select *
from (
SELECT
Products.*,
-- Following three columns will be null for deleted/missing categories
CategoryProducts.CategoryID,
CategoryProducts.CategoryName,
CategoryProducts.CategoryProductID ,
ContainerMinimumQuantity = COALESCE(nullif(Products.ContainerMinQty, 0),
Products.OrderMinimumQuantity),
CategoryProducts.IsDeleted,
CategoryProducts.SortOrder,
ROW_NUMBER() OVER(ORDER BY Products.ItemID,
Products.ManufacturerID) AS RowNum
FROM Products
LEFT JOIN CategoryProducts
ON CategoryProducts.ManufacturerID = Products.ManufacturerID
AND CategoryProducts.ItemID = Products.ItemID
-- Filter IsDeleted in join so we get nulls for deleted categories
-- And treat them the same as missing ones
AND CategoryProducts.IsDeleted = 0
LEFT JOIN Categories
ON Categories.CategoryID = CategoryProducts.CategoryID
WHERE Products.ManufacturerID = #ManufacturerID
AND (Products.ModifiedOn > #tStamp
-- Deleted/missing categories
OR CategoryProducts.ModifiedOn is null
OR CategoryProducts.ModifiedOn > #tStamp)
) C
WHERE RowNum >= #StartRow AND RowNum <= #EndRow
On a third look I don't see that Category is used at all except as a filter to CategoryProducts. If this is the case second LEFT JOIN should be changed to INNER JOIN and this section should be enclosed in parenthessis.

Resources