Update an "Order" column after deleting a row? - sql

I have a ProductsImages table which includes ImageId, Productid ,Order :
ProductId ImageId Order
----------------------------
1 1 1
1 2 2
1 3 3
1 4 4
1 5 5
When I delete a row, let's say ProductId = 1 ImageId = 1 I need to update the order column :
ProductId ImageId Order
----------------------------
1 2 1
1 3 2
1 4 3
1 5 4

After you do the delete, you can do an update:
with toupdate as (
select pi.*,
row_number() over (partition by productId order by [order]) as neworder
from ProductImages pi
)
update toupdate
set [order] = neworder;
The above updates the whole table. If you just want to update the changed product, add a where clause:
with toupdate as (
select pi.*,
row_number() over (partition by productId order by [order]) as neworder
from ProductImages pi
where pi.ProductID = #ProductId
)
update toupdate
set [order] = neworder;

Related

SQL retrieve rows based on column condition

Say I have below tables
Order Table
OrderNo CategoryID CountryID ServiceTypeID
100 1 3 1
200 2 5 2
300 3 4 4
400 1 2 9
1 service Type might belong to many category type
Category Table
ID Name ServiceTypeID
1 x 1
2 x 2
3 x 1
ServiceType table
ID Name
1 xx
2 xx
3 xx
Tracking Table
OrderNo CountryID TrackingTypeID
100 2 3
200 1 4
100 3 2
400 5 1
200 2 6
Reviewd Table
OrderNo
300
100
200
I want to write a query with below requirements
Order must belong to serviceTypeID = 1 or 2
And If the orderNo has a categoryID = 1
I want that record to be retrieved only if
there's a record in tracking table for that
orderNo with same countryID as in Order table
and if that orderNo doesn't have tracking type of id (0,7,1) in tracking table
Else for all other orders with any other category excluding orders which are not belong
to serviceTypeID = (1,2)
I want that record to be retrived only if
there's an existing record for that orderNo in
Reviewed table
and if that orderNo doesn't have tracking type of id (0,7,1) in tracking table
So basically based on above requirements the result should look like
OrderNo CategoryID StationID
100 1 3
200 2 5
select DISTINCT top 10000 o.orderNo , o.categoryID , o.serviceTypeid
,o.countrtId , Tracking.countryId
from Order o
join Tracking on o.orderNo = Tracking.orderNo
where
(o.CategoryID in (1 ) and o.countryId = Tracking.countryId
and
exists (select 1
from tracking t
where t.orderNo = o.orderNo and t.countryId =
o.countryId
)
)
OR
(o.categoryID in (select id from Category where ServiceTypeid in (7,8) and
ID not in (56 , 65)
) and
exists (select 1
from Reviewed r
where r.orderNo = o.orderNo
)
)
AND not exists
( select 1
from tracking t
WHERE T.orderNo = o.orderNo
and t.TrackingTypeID in (0 , 7 ,25))
That query seems to return only orders with ID 1 and even if it's have a trackingTypeID = 0,7,25
You could use exists and boolean logic:
select o.*
from orders o
where
(
category_id = 1
and exists (select 1 from tracking t where t.order_no = o.order_no and t.country_id = o.country_id)
)
or (
category_id = 2
and exists (select 1 from reviewed r where r.order_no = o.order_no)
)
Based on your conditions, you can use boolean logic with exists:
select o.*
from orders o
where (o.categoryid = 1 and
exists (select 1
from tracking t
where t.orderno = o.orderno and t.CountryID = o.CountryID
)
) or
(o.categoryid = 2 and
exists (select 1
from reviewed r
where r.orderno = o.orderno
)
) ;
According to your conditions this query will give results accordingly:
Select o.OrderNo,o.CategoryID,o.CountryID as StationID
from Order o
inner join Tracking t on t.OrderNo = o.OrderNo and t.CountryID = o.CountryID
where o.CategoryID = 1 or (o.CategoryID = 2
and exists (Select * from Reviewed where OrderNo = o.OrderNo))

SQL Pivot String Data

I have a tables in SQL Server: Product
Product Table:
ImageID ProductID
------- ----------
1 P1
1 P2
1 P3
2 S1
2 S2
2 S3
3 M1
This is the output that I need:
ImageID Product1ID Product2ID Product3ID
----------- ---------- ---------- ----------
1 P1 P2 P3
2 S1 S2 S3
3 M1 null null
An ImageID can have maximum 3 ProductID
It is not necessary that all ImageID will have 3 products [eg. ImageID=3]
SELECT ImageID, [Product1ID], [Product2ID], [Product3ID]
FROM
(
SELECT ImageID, ProductID
FROM ProductTable
) AS P
PIVOT
(
max( ImageID)
FOR ProductID IN ([Product1ID], [Product2ID], [Product3ID])
) AS PVT
I would just use conditional aggregation:
SELECT ImageID,
MAX(CASE WHEN seqnum = 1 THEN ProductID END) as Product1ID,
MAX(CASE WHEN seqnum = 2 THEN ProductID END) as Product2ID,
MAX(CASE WHEN seqnum = 3 THEN ProductID END) as Product3ID
FROM (SELET pt.*, ROW_NUMBER() OVER (PARTITION BY ImageId ORDER BY ProductID) as seqnum
FROM ProductTable
) P
GROUP BY ImageID;
The key idea, though, is to use ROW_NUMBER() to enumerate the products.
Your were very close, you just needed to incorporate Row_Number()
Example
Select *
From (
Select ImageID
,Item = concat('Product',row_number() over (partition by ImageID order by ProductID),'ID')
,ProductID
From ProductTable
) src
Pivot (max(ProductID) for Item in ([Product1ID], [Product2ID], [Product3ID])) pvt

How to Generate Row number Partition by two column match in sql

Tbl1
---------------------------------------------------------
Id Date Qty ReOrder
---------------------------------------------------------
1 1-1-18 1 3
2 2-1-18 0 3
3 3-1-18 2 3
4 4-1-18 3< >3
5 5-1-18 2 3
6 6-1-18 0 3
7 7-1-18 1 3
8 8-1-18 0 3
---------------------------------------------------------
I want the result like below
---------------------------------------------------------
Id Date Qty ReOrder
---------------------------------------------------------
1 1-1-18 1 3
5 5-1-18 2 3
---------------------------------------------------------
if ReOrder not same with Qty then date will be same upto after reorder=Qty
You can use cumulative approach with row_number() function :
select top (1) with ties *
from (select *, max(case when qty = reorder then 'v' end) over (order by id desc) grp
from table
) t
order by row_number() over(partition by grp order by id);
Unfortunately this will require SQL Server, But you can also do:
select *
from (select *, row_number() over(partition by grp order by id) seq
from (select *, max(case when qty = reorder then 'v' end) over (order by id desc) grp
from table
) t
) t
where seq = 1;

SQL update all records except the last one with a value

I need to make a query where only the last line of each user that has a car gets a license plate number.
ID UserId LicensePlate HasCar
1 1 ABC123 1
2 1 ABC123 1
3 2 NULL 0
4 3 UVW789 1
5 3 UVW789 1
Should become:
ID UserId LicensePlate HasCar
1 1 NULL 1
2 1 ABC123 1
3 2 NULL 0
4 3 NULL 1
5 3 UVW789 1
So I basically need to find all users with a licenseplate and change all but the last one and make the LicensePlate NULL
Assuming the ID column is an identity column so it can provide the ordering, something like this should do the trick:
;WITH CTE AS
(
SELECT Id,
UserId,
LicensePlate,
ROW_NUMBER() OVER(PARTITION BY UserId ORDER BY Id DESC) rn
FROM Table
WHERE HasCar = 1
)
UPDATE CTE
SET LicensePlate = NULL
WHERE rn > 1
You can try this
UPDATE l
SET l.LicensePlate = null
FROM Car l
INNER JOIN (SELECT UserId, Max(Id) AS max_id
FROM Car
GROUP BY UserId) m ON m.UserId = l.UserId
AND m.max_id <> l.id
You can do it with a join on the table itself like that :
UPDATE car c
INNER JOIN car c2 ON c.userId = c2.userId AND c.id < c2.id AND c.HasCar = 1 AND c2.HasCar = 1
SET c.LicensePlate = NULL
The condition c.id < c2.id will avoid to select the last line
By using LAG Function also you can achieve it.
;WITH License(ID,UserId,LicensePlate,HasCar)
as
(
SELECT 1,1,'ABC123',1 UNION ALL
SELECT 2,1,'ABC123',1 UNION ALL
SELECT 3,2,NULL ,0 UNION ALL
SELECT 4,3,'UVW789',1 UNION ALL
SELECT 5,3,'UVW789',1
)
SELECT ID,UserId,LAG(LicensePlate,1,NULL) OVER(PARTITION BY UserId ORDER BY LicensePlate),HasCar FROM License

SQL group by with NULL

I have a table something like this:
ID ProductID ProductName Price
== ========= =========== =====
1 XX1 TShirt 10
2 XX1 TShirt 10
3 NULL TShirt 10
4 XX2 Shirt 20
5 XX3 Shirt1 30
Now I want this to group by ProductName and results will be as follows
ID ProductID ProductName Price
== ========= =========== =====
1 XX1 TShirt 30
4 XX2 Shirt 20
5 XX3 Shirt1 30
Thanks
ProductID seems to be irrelevant for the group, so don't use it. To get all columns you could use a CTE and a ranking function like ROW_NUMBER:
WITH CTE AS(
SELECT ID,
ProductID,
ProductName,
Price = SUM(Price) OVER (PARTITION BY ProductName),
RN = ROW_NUMBER() OVER (PARTITION BY ProductName ORDER BY ID)
FROM dbo.TableName
)
SELECT CTE.* FROM CTE
WHERE RN = 1
If you want to take the row which contains the ProductID(where it is not NULL) modify the ORDER BY:
WITH CTE AS(
SELECT ID,
ProductID,
ProductName,
Price = SUM(Price) OVER (PARTITION BY ProductName),
RN = ROW_NUMBER() OVER (PARTITION BY ProductName
ORDER BY CASE WHEN ProductID IS NOT NULL
THEN 0 ELSE 1 END, ID)
FROM dbo.TableName
)
SELECT CTE.* FROM CTE
WHERE RN = 1