SQL Server ISNULL not working in multi table selection - sql-server

I'm very new to SQL server and I'm trying to get the maximum price of an item based on the update of table and if is null to replace the null able value with zero.
Here is what I did:
DECLARE #itemid BIGINT
SELECT
(SELECT ISNULL(MAX(ITEM_SUPPLIER_PRICE.Price), 0.00)
FROM ITEM_SUPPLIER_PRICE
WHERE (ITEM_SUPPLIER_PRICE.item_id = 7)) AS price,
itemunits.unit_id,
itemunits.unit_name
FROM
ITEM_SUPPLIER_PRICE
INNER JOIN
Items ON ITEM_SUPPLIER_PRICE.item_id = Items.Item_id
INNER JOIN
itemunits ON Items.Item_unit_id = itemunits.unit_id
WHERE
(Items.Item_id = 7)
GROUP BY
itemunits.unit_id, itemunits.unit_name,
ITEM_SUPPLIER_PRICE.update_date
ORDER BY
ITEM_SUPPLIER_PRICE.update_date DESC;

I think you're just looking for the max price in the group. Since prices probably can't be negative, the second option below should be equivalent but I throw it in just in case the problem is there.
SELECT
COALESCE(MAX(isp.Price), 0.00) AS price1,
MAX(COALESCE(isp.Price, 0.00)) AS price2,
iu.unit_id,
iu.unit_name
FROM ITEM_SUPPLIER_PRICE isp
INNER JOIN Items i ON i.item_id = isp.Item_id
INNER JOIN itemunits iu ON iu.unit_id = i.Item_unit_id
WHERE i.Item_id = 7
GROUP BY
iu.unit_id,
iu.unit_name,
isp.update_date
ORDER BY isp.update_date desc;

Related

Update multiple tables with multiple rows with trigger

I have these tables Users, UserPackages, Packages, Refers.
Users table has columns UserRef_NO (his own unique number), RefNo (if he registered using someones reference number) and Refarning (where he/she gets earning if someone registered using his refNo and bought a package and package status changed to 'True').
UserPackages table has columns U_ID (foreign key to Users), P_ID (foreign key to Packages), PackageStatus (true if bought false if not), BuyDate (generated as soon as PackageStatus changes to true), ExpiryDate (calculated from the join of Packages table and BuyDate where validity is total days of Packages)
Packages table has columns Price, ReferComission (in percentage), Validity (in days).
EDIT:- Third Edit this works fine for single row updates but fails for multi row updates saying subquery returned more then one value
alter TRIGGER [dbo].[HeavyTriggerTest] ON [dbo].[UserPackages]
after update
as
update UP set
BuyDate = GETDATE(), Expirydate = dateadd(dd, P.Validitiy, getdate())
from dbo.UserPackages UP
inner join Inserted I on I.P_ID = UP.P_ID and I.U_ID = UP.U_ID
inner join dbo.Packages P on P.PID = I.P_ID
where UP.PackageStatus = 'True';
;
with firstCte(Name,UID,PName,Price,ReferComission,ReferredBy)
as
(
select distinct Users.Name,Users.ID,Packages.PName,Packages.Price,Packages.ReferCommission,(select DISTINCT ID from Users
where Users.UserRef_No=Refers.RefOf )
from Users inner join UserPackages on UserPackages.U_ID=Users.ID
inner join Packages on Packages.PID=UserPackages.P_ID
inner join Refers on Users.Ref_No=Refers.RefOf
inner join Inserted I on I.U_ID = UserPackages.U_ID and I.P_ID = UserPackages.P_ID
and UserPackages.PackageStatus='true' AND UserPackages.U_ID=i.U_ID
AND Refers.RefOf=(SELECT users.Ref_No where UserPackages. U_ID=i.U_ID)
)
update Users set RefEarning+= Price*ReferComission/100 from firstCte where ID=ReferredBy ;
update Users set Active='True' where ID=(select U_ID from inserted) and Active='False'
and here's the single update query which i tried to replace with above last two updates but it gives wrong results plus it also doesn't work for multiple row updates
update Users set RefEarning+=(
case when ID=firstCte.ReferredBy then firstCte.Price*ReferComission/100 else RefEarning end)
,Active=case when ID=(select U_ID from inserted) and Active='false' then 'True'
when firstCte.ReferredBy=(select U_ID from inserted) then 'true' else Active end
from firstCte
Your second query, first update, you need to join Inserted on as:
update UP set
BuyDate = GETDATE(), Expirydate = dateadd(dd, P.Validitiy, getdate())
from dbo.UserPackages UP
inner join Inserted I on I.P_IP = UP_P_ID and I.U_ID = UP.U_ID
inner join dbo.Packages P on P.PID = I.P_ID
where UP.PackageStatus = 'True';
Note the table aliases which I recommended to you in your last question - they make it much easier to read through a query.
Also note its best practice to schema qualify your tables.
Second query, second update:
with firstCte ([Name], [UID], PName, Price, ReferComission, ReferredBy)
as
(
select U.[Name], U.ID, P.PName, P.Price, P.ReferCommission
, max(U.ID) over () as referedby
from Users U
inner join UserPackages UP on UP.U_ID = U.ID
inner join Packages P on P.PID = UP.P_ID
inner join Refers R on R.RefOf = U.Ref_No
inner join Inserted I on I.U_ID = UP.U_ID and I.P_ID = UP.P_ID
where UP.PackageStatus='true'
)
update U set
Active = 'True'
, RefEarning += Price*ReferComission/100
from Users U
inner join firstCte on ReferredBy = U.id
where Active = 'False';
Note the window function max to avoid repeating the query in a sub-query.
Note joining the CTE to the Users table to perform the update.

Filtering date after max date SQL

I have a table with values en date/timstamps. This table is dbo.meterdata.value. The output that i want to see is as followed: The latest date/timestamp (Max) but only the ones where te latest date/timestamp is last week. My Query is:
SELECT dbo.meter.DataImportCode
,dbo.meter.NAME
,dbo.company.NAME
,dbo.meter.MeterNumber
,MAX(dbo.meterdata.RoundedTimeStamp) AS 'laatste datum'
,dbo.MeterOperator.Description
,dbo.meter.CumulativeReadings
FROM dbo.meter
LEFT OUTER JOIN DBO.MeterData ON dbo.meter.MeterID = dbo.meterdata.MeterID
JOIN DBO.Site ON dbo.meter.SiteID = dbo.site.SiteID
JOIN DBO.Company ON dbo.site.CompanyID = dbo.company.CompanyID
JOIN DBO.MeterOperator ON dbo.meter.MeterOperatorID = dbo.MeterOperator.MeterOperatorID
--WHERE (select (dbo.meterdata.roundedtimestamp) from dbo.MeterData) < DateAdd(DD,-7,GETDATE() )
AND dbo.meterdata.RoundedTimeStamp IS NOT NULL
GROUP BY dbo.meter.DataImportCode
,dbo.company.NAME
,dbo.meter.NAME
,dbo.meter.MeterNumber
,dbo.MeterOperator.Description
,dbo.meter.CumulativeReadings
Example of the unfilterd result:
Example
Thank you for help and support
Try the following:
select dbo.meter.DataImportCode, dbo.meter.Name, dbo.company.Name, dbo.meter.MeterNumber,MAX(dbo.meterdata.RoundedTimeStamp) AS 'laatste datum', dbo.MeterOperator.Description, dbo.meter.CumulativeReadings
from dbo.meter
LEFT OUTER JOIN DBO.MeterData ON dbo.meter.MeterID = dbo.meterdata.MeterID
JOIN DBO.Site on dbo.meter.SiteID = dbo.site.SiteID
JOIN DBO.Company on dbo.site.CompanyID = dbo.company.CompanyID
JOIN DBO.MeterOperator on dbo.meter.MeterOperatorID = dbo.MeterOperator.MeterOperatorID
--WHERE (select (dbo.meterdata.roundedtimestamp) from dbo.MeterData) < DateAdd(DD,-7,GETDATE() )
--AND dbo.meterdata.RoundedTimeStamp is not null
GROUP BY dbo.meter.DataImportCode, dbo.company.name, dbo.meter.Name, dbo.meter.MeterNumber, dbo.MeterOperator.Description, dbo.meter.CumulativeReadings
HAVING [laatste datum] < DateAdd(day,-7,GETDATE())
If I understood you right, what you want to do is filter out the data after it has been grouped. This is done using the HAVING clause of the SELECT statement, as the above query depicts.

SQL combine two queries result into one dataset

I am trying to combine two SQL queries the first is
SELECT
EAC.Person.FirstName,
EAC.Person.Id,
EAC.Person.LastName,
EAC.Person.EmployeeId,
EAC.Person.IsDeleted,
Controller.Cards.SiteCode,
Controller.Cards.CardCode,
Controller.Cards.ActivationDate,
Controller.Cards.ExpirationDate,
Controller.Cards.Status,
EAC.[Group].Name
FROM
EAC.Person
INNER JOIN
Controller.Cards ON EAC.Person.Id = Controller.Cards.PersonId
INNER JOIN
EAC.GroupPersonMap ON EAC.Person.Id = EAC.GroupPersonMap.PersonId
INNER JOIN
EAC.[Group] ON EAC.GroupPersonMap.GroupId = EAC.[Group].Id
And the second one is
SELECT
IsActive, ActivationDateUTC, ExpirationDateUTC,
Sitecode + '-' + Cardcode AS Credential, 'Badge' AS Type,
CASE
WHEN isActive = 0
THEN 'InActive'
WHEN ActivationDateUTC > GetUTCDate()
THEN 'Pending'
WHEN ExpirationDAteUTC < GetUTCDate()
THEN 'Expired'
ELSE 'Active'
END AS Status
FROM
EAC.Credential
JOIN
EAC.WiegandCredential ON Credential.ID = WiegandCredential.CredentialId
WHERE
PersonID = '32'
Where I would like to run the second query for each user of the first query using EAC.Person.Id instead of the '32'.
I would like all the data to be returned in one Dataset so I can use it in Report Builder.
I have been fighting with this all day and am hoping one of you smart guys can give me a hand. Thanks in advance.
Based on your description in the comments, I understand that the connection between the two datasets is actually the PersonID field, which exists in both EAC.Credential and EAC.Person; however, in EAC.Credential, duplicate values exist for PersonID, and you want only the most recent one for each PersonID.
There are a few ways to do this, and it will depend on the number of rows returned, the indexes, etc., but I think maybe you're looking for something like this...?
SELECT
EAC.Person.FirstName
,EAC.Person.Id
,EAC.Person.LastName
,EAC.Person.EmployeeId
,EAC.Person.IsDeleted
,Controller.Cards.SiteCode
,Controller.Cards.CardCode
,Controller.Cards.ActivationDate
,Controller.Cards.ExpirationDate
,Controller.Cards.Status
,EAC.[Group].Name
,X.IsActive
,X.ActivationDateUTC
,X.ExpirationDateUTC
,X.Credential
,X.Type
,X.Status
FROM EAC.Person
INNER JOIN Controller.Cards
ON EAC.Person.Id = Controller.Cards.PersonId
INNER JOIN EAC.GroupPersonMap
ON EAC.Person.Id = EAC.GroupPersonMap.PersonId
INNER JOIN EAC.[Group]
ON EAC.GroupPersonMap.GroupId = EAC.[Group].Id
CROSS APPLY
(
SELECT TOP 1
IsActive
,ActivationDateUTC
,ExpirationDateUTC
,Sitecode + '-' + Cardcode AS Credential
,'Badge' AS Type
,'Status' =
CASE
WHEN isActive = 0
THEN 'InActive'
WHEN ActivationDateUTC > GETUTCDATE()
THEN 'Pending'
WHEN ExpirationDateUTC < GETUTCDATE()
THEN 'Expired'
ELSE 'Active'
END
FROM EAC.Credential
INNER JOIN EAC.WiegandCredential
ON EAC.Credential.ID = EAC.WiegandCredential.CredentialId
WHERE EAC.Credential.PersonID = EAC.Person.PersonID
ORDER BY EAC.Credential.ID DESC
) AS X
-- Optionally, you can also add conditions to return specific rows, i.e.:
-- WHERE EAC.Person.PersonID = 32
This option uses a CROSS APPLY, which means that every row of the first dataset will return additional values from the second dataset, based on the criteria that you described. In this CROSS APPLY, I'm joining the two datasets based on the fact that PersonID exists in both EAC.Person (in your first dataset) as well as in EAC.Credential. I then specify that I want only the TOP 1 row for each PersonID, with an ORDER BY specifying that we want the most recent (highest) value of ID for each PersonID.
The CROSS APPLY is aliased as "X", so in your original SELECT you now have several values prefixed with the X. alias, which just means that you're taking these fields from the second query and attaching them to your original results.
CROSS APPLY requires that a matching entry exists in both subsets of data, much like an INNER JOIN, so you'll want to check and make sure that the relevant values exist and are returned correctly.
I think this is pretty close to the direction you're trying to go. If not, let me know and I'll update the answer. Good luck!
Try like this;
select Query1.*, Query2.* from (
SELECT
EAC.Person.FirstName,
EAC.Person.Id as PersonId,
EAC.Person.LastName,
EAC.Person.EmployeeId,
EAC.Person.IsDeleted,
Controller.Cards.SiteCode,
Controller.Cards.CardCode,
Controller.Cards.ActivationDate,
Controller.Cards.ExpirationDate,
Controller.Cards.Status,
EAC.[Group].Name
FROM
EAC.Person
INNER JOIN
Controller.Cards ON EAC.Person.Id = Controller.Cards.PersonId
INNER JOIN
EAC.GroupPersonMap ON EAC.Person.Id = EAC.GroupPersonMap.PersonId
INNER JOIN
EAC.[Group] ON EAC.GroupPersonMap.GroupId = EAC.[Group].Id)
Query1 inner join (SELECT top 100
IsActive, ActivationDateUTC, ExpirationDateUTC,
Sitecode + '-' + Cardcode AS Credential, 'Badge' AS Type,
CASE
WHEN isActive = 0
THEN 'InActive'
WHEN ActivationDateUTC > GetUTCDate()
THEN 'Pending'
WHEN ExpirationDAteUTC < GetUTCDate()
THEN 'Expired'
ELSE 'Active'
END AS Status
FROM
EAC.Credential
JOIN
EAC.WiegandCredential ON Credential.ID = WiegandCredential.CredentialId
ORDER BY EAC.Credential.ID DESC) Query2 ON Query1.PersonId = Query2.PersonID
Just select two queries to join them like Query1 and Query2 by equaling PersonId data.

Linq results different than the sql result

I am having an MVC4 web application where I am using LINQ.
I have the below query which results 53 rows in SQL.
select * from table1 t join
[table2] tpf on t.TestID=tpf.TestID
join
table3 pf on tpf.Test2ID =pf.Test2ID
join table4 pfp on
pf.Test3ID = pfp.Test3ID
join table5 p on pfp.Test5ID = p.Test5ID where t.testtypeid=1
order by pfp.Test3ID,pf.Test2ID
If I convert the same query as below it returns more records.
trvm.MyTestVMs = (
from tt in db.table1s
join ttpf in db.table2s on tt.TestID equals ttpf.TestID
join pf in db.table3s on ttpf.Test2ID equals pf.Test2ID
join pfp in db.table4s on pf.Test3ID equals pfp.Test3ID
join p in table5s on pfp.Test5ID equals p.Test5ID
where tt.testtypeid == 1
orderby pfp.Test3ID
orderby pf.Test2ID
select new MyTestVM
{
FamilyID = pf.Test2ID,
ProductID = p.Test3ID,
Desc = p.Description
}
).ToList();
The result which is getting from SQL and the above LINQ varies. Actually, there are some duplicate result I am getting from the LINQ query. What is causing this difference?
It turns out that the LINQ query is not equivalent to the SQL query posted due to the usage of a products query variable (not shown in the post) which causes one of the many-to-many link table to be included twice, thus producing more records.
One way to fix the problem is to replace products with db.Products and apply the same filters as in the query variables you were trying to reuse.
But if you want to reuse query variables, then here is the correct way to do that:
// Eliminate the need of DbFunctions.TruncateTime(dt) inside the queries
dt = dt.Date;
// Queries
var productFamilys = (
from tt in db.TestTypes
join ttpf in db.TestTypeProductFamilys on tt.TestTypeID equals ttpf.TestTypeID
join pf in db.ProductFamilys on ttpf.ProductFamilyID equals pf.ProductFamilyID
where tt.TestTypeID == TestTypeID
where DbFunctions.TruncateTime(pf.StartDate) <= dt
where DbFunctions.TruncateTime(pf.EndDate) > dt
select pf
);
var productFamilyProducts = (
from pf in productFamilys
join pfp in db.ProductFamilyProducts on pf.ProductFamilyID equals pfp.ProductFamilyID
join p in db.Products on pfp.ProductID equals p.ProductID
where DbFunctions.TruncateTime(p.StartDate) <= dt
where DbFunctions.TruncateTime(p.EndDate) > dt
select new { Family = pf, Product = p }
);
var products = (
from pfp in productFamilyProducts
select pfp.Product
);
var productFamilyProductVMs = (
from pfp in productFamilyProducts
orderby pfp.Product.ProductID, pfp.Family.ProductFamilyID
select new ProductFamilyProductVM
{
ProductFamilyID = pfp.Family.ProductFamilyID,
ProductID = pfp.Product.ProductID,
ProdDesc = pfp.Product.Description
}
);
// Results
trvm.ProductFamilys = productFamilys.ToList();
trvm.Products = products.ToList();
trvm.ProductFamilyProductVMs = productFamilyProductVMs.ToList();
Now the SQL for the last query (the one in question) looks like this
SELECT
[Project1].[ProductFamilyID] AS [ProductFamilyID],
[Project1].[ProductID] AS [ProductID],
[Project1].[Description] AS [Description]
FROM ( SELECT
[Extent2].[ProductFamilyID] AS [ProductFamilyID],
[Extent4].[ProductID] AS [ProductID],
[Extent4].[Description] AS [Description]
FROM [dbo].[TestTypeProductFamilies] AS [Extent1]
INNER JOIN [dbo].[ProductFamilies] AS [Extent2] ON [Extent1].[ProductFamilyID] = [Extent2].[ProductFamilyID]
INNER JOIN [dbo].[ProductFamilyProducts] AS [Extent3] ON [Extent2].[ProductFamilyID] = [Extent3].[ProductFamilyID]
INNER JOIN [dbo].[Products] AS [Extent4] ON [Extent3].[ProductID] = [Extent4].[ProductID]
WHERE ([Extent1].[TestTypeID] = #p__linq__0) AND ((convert (datetime2, convert(varchar(255), [Extent2].[StartDate], 102) , 102)) <= #p__linq__1) AND ((convert (datetime2, convert(varchar(255), [Extent2].[EndDate], 102) , 102)) > #p__linq__2) AND ((convert (datetime2, convert(varchar(255), [Extent4].[StartDate], 102) , 102)) <= #p__linq__3) AND ((convert (datetime2, convert(varchar(255), [Extent4].[EndDate], 102) , 102)) > #p__linq__4)
) AS [Project1]
ORDER BY [Project1].[ProductID] ASC, [Project1].[ProductFamilyID] ASC
i.e. pretty similar to the sample SQL query and should produce the same results.
Result is different because in your second query , you have two "OrderBy" and because of that, the second OrderBy it's works over the collection which is result of first "OrderBy" and is reordering the items.
Change
orderby pfp.ProductID
orderby pf.ProductFamilyID
from your second query in
orderby pfp.ProductID, pf.ProductFamilyID
to get same results

SQL Select random from multiple table and order by specific criteria on one table

I need to select a random record from 3 tables and ensure I am ordering by photoOrder
Select TOP 1(a.id), a.mls_number, a.parcel_name, a.property_type, a.ownership_type, b.filename, b.photoOrder, c.county_Name
From property as a
Inner JOIN
listingPhotos as b on a.id = b.ListingID
LEFT JOIN
counties as C on a.county_name = c.id
WHERE a.isCommercial = 'True'
Order By NEWID()
So this query works, but I need to ensure that the b.filename record is ordered by b.photoOrder and thus the b.photoOrder should always be 1.
The b table (listing photos) has multiple photo files per property and I need to only select the photo that is 1st in the photo order.
Thanks
You could subquery your listingPhotos table and limit to WHERE PhotoOrder = 1:
Select TOP 1(a.id), a.mls_number, a.parcel_name, a.property_type, a.ownership_type, b.filename, b.photoOrder, c.county_Name
From property as a
Inner JOIN
(SELECT ListingID , filename, PhotoOrder FROM listingPhotos WHERE PhotoORder = 1
) as b on a.id = b.ListingID
LEFT JOIN
counties as C on a.county_name = c.id
WHERE a.isCommercial = 'True'
Order By NEWID()

Resources