LIMIT equivalent for SQL Server 2012 in an UPDATE statement - sql

I have the following table below and am trying to update the first available row with an user ID through a query, but I need to limit this to only update one row and not multiple.
ID Model UserID
1 X12T5 1
2 X13T5 2
3 X14T5 NULL
4 X15T5 NULL
The first available row would be where ID is 3. I would update it with the following query:
UPDATE Table SET UserID = '3' WHERE UserID IS NULL
But I want to make sure it affects only 1 row and not multiple that are available, LIMIT doesn't exist in SQL Server.
What would the best way to achieve this?

You can do this with UPDATE TOP. It's the equivalent of a SELECT TOP but for updates; and TOP is SQL Server's equivalent of MySQL's LIMIT.
See further info.

UPDATE Table SET UserID = '3'
WHERE UserID IS NULL
AND Id IN (SELECT top 1 ID FROM table where UserId IS NULL)

You can also use any of the following methods (Assuming column ID is of integer datatype)
Using subquery :
UPDATE a
SET a.UserID='3'
FROM YourTable a
WHERE ID =( SELECT MIN(ID)
FROM YourTable
WHERE UserID is NULL)
Using JOIN:
UPDATE a
SET a.UserID='3'
FROM YourTable a
JOIN
( SELECT MIN(ID) MinId
FROM YourTable
WHERE UserID is NULL) b
ON a.ID=b.MinId
Using CTE
WITH cte_a
AS
(SELECT MIN(ID) MinId
FROM YourTable
WHERE UserID is NULL)
UPDATE a
SET a.UserID='3'
FROM YourTable a
JOIN cte_a b a.ID=b.MinId

You can also use CTE & perform the SELECT\UPDATE\DELETE operations ,
; WITH CTE AS (
SELECT TOP 10 * FROM TABLE
)
UPDATE CTE
SET ...
DELETE\UPDATE\SELECT works with CTE ... Cool !!!

Related

Alter a column to indicate there are duplicates in a separate column?

I have a table in which one of the columns, column_A has duplicate values. I also have a blank column_indicator which I would like to populate with 1s for all cases where the value in column_A occurs more than once.
I know how to SELECT the duplicates and have used the following formula:
SELECT [dbo].[myTable].[column_A], COUNT(*)
FROM [dbo].[myTable]
GROUP BY [dbo].[myTable].[column_A]
HAVING COUNT(*) > 1
How do I update column_indicator? I have tried:
UPDATE [dbo].[myTable]
SET [dbo].[myTable].[column_indicator] = 1
WHERE
GROUP BY [dbo].[myTable].[column_A]
HAVING COUNT(*) > 1
I know I am off base but cannot figure out how to proceed with this column update.
You can do a window count in a common table expression and then update it:
WITH cte AS (
SELECT
[column_indicator],
[column_A],
COUNT(*) OVER(PARTITION BY [column_A]) cnt
FROM [dbo].[myTable]
)
UPDATE cte SET [column_indicator] = 1 WHERE cnt > 1
I think you can also use a nested update query to solve this.
UPDATE [dbo].[myTable] SET [column_indicator] = 1
FROM
(
SELECT a.[column_A],a.[column_indicator], COUNT(*) AS COUNT
FROM (select [dbo].[myTable].[column_A],[dbo].[myTable].[column_indicator]
from [dbo].[myTable]) a
GROUP BY a.[column_A],a.[column_indicator]
having COUNT > 1
) t
WHERE [dbo].[myTable].[column_A] = t.[column_A];

Update with Where, Order by and Limit does not work

I am using SQLite 3.
When I input the following query
UPDATE MyTable Set Flag = 1 WHERE ID = 5 Order By OrderID DESC LIMIT 1;
I will always get an error:
near Order By, syntax error
I cannot figure out what is the problem with my query
To use LIMIT and ORDER BY in an UPDATE or DELETE statement, you have to do two things:
Build a custom version of the sqlite3.c amalgamation from source, configuring it with the --enable-update-limit option.
Compile that custom sqlite3.c into your project with SQLITE_ENABLE_UPDATE_DELETE_LIMIT defined to 1.
"Order By OrderID DESC LIMIT 1" is for selecting top one ordered result
so you should use it in select query.
you should do a subquery where you first get the id and then update it:
UPDATE MyTable
SET Flag = 1
WHERE (ID,OrderID) IN (SELECT ID,OrderID
FROM MyTable
WHERE ID = 5
ORDER BY OrderID DESC LIMIT 1);
Demo
You could use ROWID:
UPDATE MyTable
SET Flag = 1
WHERE ROWID IN (SELECT ROWID FROM MyTable WHERE ID = 5
ORDER BY OrderID DESC LIMIT 1);
db<>fiddle demo
or (ID,OrderID) tuple:
UPDATE MyTable
SET Flag = 1
WHERE (ID, ORDERID) IN (SELECT ID, ORDERID FROM MyTable WHERE ID = 5
ORDER BY OrderID DESC LIMIT 1);
db<>fiddle demo2
And if you need to do it in bulk for every ID(SQLite 3.25.0):
WITH cte AS (
SELECT *,ROW_NUMBER() OVER(PARTITION BY ID ORDER BY OrderID DESC) AS rn FROM tab
)
UPDATE tab
SET Flag = 1
WHERE (ID, OrderID) IN (
SELECT ID, OrderID
FROM cte
WHERE rn = 1
);
Order By statement will not work in update query.
You have to use alternate way
UPDATE MyTable Set Flag = 1 WHERE ID = 5
and OrderId = (select max(OrderId) from MyTable where Id = 5);
If you have used the query like above it will work.
Introduction
Below I'm presenting two solutions to solve the issue and perform a proper UPDATE. At the end of each solution there's a live example on sample data included.
First does not require you to input any id and works for the entire table by picking the latest orderid for each id and changing it's flag to 1
Second requires you to input an id and works only for updating one id on the run
I'd personally go with first solution, but I am not sure about your requirement, thus posting two possibilities.
First solution - update entire table
Explanation here, for code scroll down.
For this we will use Row Value construction (id, orderid) just like for the second solution.
It will find the latest row based on orderid and update only that row for given (id, orderid) pair. More on that is included in Explanation of second solution.
We will also need to simulate row_number function to assign each row ranking numbers, to find out which row has the latest orderid for every id and mark then as 1 to be able to pull only those for update. This will allow us to update multiple rows for different ids in one statement. SQLite will have this functionality built in version 3.2.5 but for now, we will work with a subquery.
To generate row numbers we will use this:
select
*,
(select count(*) from mytable m1 where m1.id = m2.id and m1.orderid >= m2.orderid) as rn
from mytable m2
Then we just need to filter the output on rn = 1 and we have what we need.
That said, the whole UPDATE statement will look like:
Code
update mytable
set flag = 1
where (id,orderid) in (
select id, orderid
from (
select *, (select count(*) from mytable m1 where m1.id = m2.id and m1.orderid >= m2.orderid) as rn
from mytable m2
) m
where
m.rn = 1
and m.id = mytable.id
);
Live DEMO
Here's db fiddle to see this solution live on sample data.
Second solution - update only one ID
If you know your ID to be updated and want to run UPDATE statement for only one id, then this will work:
Code
update mytable
set flag = 1
where (id,orderid) in (
select id, orderid
from mytable
where id = 5
order by orderid desc
limit 1
);
Explanation
(id, orderid) is a construction called Row Value for which SQLite compares scalar values from left to right.
Example taken from documentation:
SELECT (1,2,3) = (1,2,3) -- outputs: 1
Live DEMO
Here's db fiddle to see this solution live on sample data.
SQL
UPDATE MyTable
SET Flag = 1
WHERE ID = 5
AND OrderID IN (SELECT OrderID
FROM MyTable
WHERE ID = 5
ORDER BY OrderID DESC
LIMIT 1);
Demo
SQLFiddle demo: http://sqlfiddle.com/#!5/6d596/2

Select a NON-DISTINCT column in a query that return distincts rows

The following query returns the results that I need but I have to add the ID of the row to then update it. If I add the ID directly in the select statement it will return me more results then I need because each ID is unique so the DISTINCT statement see the line as unique.
SELECT DISTINCT ucpse.MemberID, ucpse.ProductID, ucpse.UserID
FROM UserCustomerProductSalaryExceptions as ucpse
WHERE EXISTS (SELECT NULL
FROM UserCustomerProductSalaryExceptions as upcse2
WHERE ucpse.userid = upcse2.userid AND ucpse.MemberID = upcse2.MemberID AND ucpse.ProductID = upcse2.ProductID
GROUP BY upcse2.UserID, upcse2.memberid, upcse2.productid
HAVING COUNT(UserID) >= 2
)
So basically I need to add ucpse.ID in the Select statement while keeping DISTINCT values for MemberID,ProductID and UserID.
Any Ideas ?
Thank you
According to you comment:
If the data has been duplicated 67 times for a given employee with a given product and a given client, I need to keep only one of thoses records. It's not important which one, so this is why I use DISTINC to obtain unique combinaison of given employee with a given product and a given client.
You can use MIN() or MAX() and GROUP BY instead of DISTINCT
SELECT MAX(ucpse.ID) AS ID, ucpse.MemberID, ucpse.ProductID, ucpse.UserID
FROM UserCustomerProductSalaryExceptions as ucpse
WHERE EXISTS (SELECT NULL
FROM UserCustomerProductSalaryExceptions as upcse2
WHERE ucpse.userid = upcse2.userid AND ucpse.MemberID = upcse2.MemberID AND ucpse.ProductID = upcse2.ProductID
GROUP BY upcse2.UserID, upcse2.memberid, upcse2.productid
HAVING COUNT(UserID) >= 2
)
GROUP BY ucpse.MemberID, ucpse.ProductID, ucpse.UserID
UPDATE:
From you comments I think the below query is what you need
DELETE FROM UserCustomerProductSalaryExceptions
WHERE ID NOT IN ( SELECT MAX(ucpse.ID) AS ID
FROM #UserCustomerProductSalaryExceptions
GROUP BY ucpse.MemberID, ucpse.ProductID, ucpse.UserID
HAVING COUNT(ucpse.ID) >= 2
)
If all you want is to delete the duplicates, this will do it:
WITH X AS
(SELECT ID,
ROW_NUMBER() OVER (PARTITION BY MemberID, ProductID, UserID ORDER BY ID) AS DupRowNum<br
FROM UserCustomerProductSalaryExceptions
)
DELETE X WHERE DupRowNum > 1
ID's not necessary - try:
UPDATE uu SET
<your settings here>
FROM UserCustomerProductSalaryExceptions uu
JOIN ( <paste your entire query above here>
) uc ON uc.MemberID=uu.MemberId AND uc.ProductID=uu.ProductId AND uc.UserID=uu.UserId
From the sound of your data structure (which I would STRONGLY advise normalizing as soon as possible), it sounds like you should be updating all the records. It sounds as if each duplicate is important because it contains some information about an employee's relation to a customer or product.
I would probably update all the records. Try this:
UPDATE UCPSE
SET
--Do your updates here
FROM UserCustomerProductSalaryExceptions as ucpse
JOIN
(
SELECT UserID, MemberID, ProductID
FROM UserCustomerProductSalaryExceptions
GROUP BY UserID, MemberID, ProductID
HAVING COUNT(UserID) >= 2
) T
ON ucpse.UserID = T.UserID AND ucpse.MemberID = T.MemberID AND ucpse.ProductID = T.ProductID

SQL query exclude rows if having two different values

Basically my select statement returns below:
ID Status
100 1
100 2
101 1
What i'm looking for is to return if a ID having status as 1 and if the same ID has another status ID as 2 then exclude both
In Short results as below:
ID Status
101 1
Thanks in advance !
The following query returns ID values that occur only once.
SELECT ID
FROM t
GROUP BY ID
HAVING COUNT(*) = 1
It should be sufficient for the sample data you provided. If there are other cases then let me know.
SQL Fiddle
You gonna need subquery and NOT IN here.
The following would work if you have column status as INT datatype
SELECT *
FROM table
WHERE status = 1
AND ID NOT IN (
SELECT ID
FROM table
WHERE status = 2
);
Making a generic query, which will remove all duplicated rows, not only for a particular ID :
select ID
from table where ID NOT IN
(select ID from table GROUP BY ID HAVING count(Status) > 1)
/* Subquery will fetch ID's having multiple entries*/
SQL Fiddle
The CTE 'IDs' retrieves all IDs which have single record in DB. This is then joined to original table to return the result as a pair (ID, Status)
;with IDs as
(
select ID
from yourtable
group by ID
having count(*) = 1
)
select i.ID, y.Status
from yourtable y
inner join IDs i on y.ID = i.ID
order by i.ID

Deletion of duplicate records using one query only

I am using SQL server 2005.
I have a table like this -
ID Name
1 a
1 a
1 a
2 b
2 b
3 c
4 d
4 d
In this, I want to delete all duplicate entries and retain only one instance as -
ID Name
1 a
2 b
3 c
4 d
I can do this easily by adding another identity column to this table and having unique numbers in it and then deleting the duplicate records. However I want to know if I can delete the duplicate records without adding that additional column to this table.
Additionally if this can be done using only one query statement. i.e. Without using Stored procedures or temp tables.
Using a ROW_NUMBER in a CTE allows you to delete duplicate values while retaining unique rows.
WITH q AS (
SELECT RN = ROW_NUMBER() OVER (PARTITION BY ID ORDER BY ID )
, ID
, Name
FROM ATable
)
DELETE FROM q WHERE RN > 1
Lieven is Right... however you may want to tweak lieven's code by just adding a top clause in the delete statement like this:
delete top(1) from q where RN > 1;
Hope this helps
You may use this query:
delete a from
(select id,name, ROW_NUMBER() over (partition by id,name order by id) row_Count
from dup_table) a
where a.row_Count >1
delete from table1
USING table1, table1 as vtable
WHERE (NOT table1.ID=vtable.ID)
AND (table1.Name=vtable.Name)
DELETE FROM tbl
WHERE ID NOT IN (
SELECT MIN(ID)
FROM tbl
GROUP BY Name
)