CREATE TABLE Products(Id INT, Name CHAR(100), DefaultImageId INT NULL);
INSERT INTO Products (Id, Name, DefaultImageId) VALUES(1, 'A', NULL);
INSERT INTO Products (Id, Name, DefaultImageId) VALUES(2, 'A', NULL);
INSERT INTO Products (Id, Name, DefaultImageId) VALUES(3, 'A', NULL);
INSERT INTO Products (Id, Name, DefaultImageId) VALUES(4, 'A', NULL);
INSERT INTO Products (Id, Name, DefaultImageId) VALUES(5, 'A', NULL);
INSERT INTO Products (Id, Name, DefaultImageId) VALUES(1, 'B', NULL);
INSERT INTO Products (Id, Name, DefaultImageId) VALUES(2, 'B', NULL);
INSERT INTO Products (Id, Name, DefaultImageId) VALUES(3, 'B', NULL);
In general, I would update a table randomly like the following scripts.
update a
set DefaultImageId=1
from Products as a
where name = 'A'
and id in (
select top 2 id
from Products as b
where a.name = b.name
order by newid()
)
However, I get some issue. It would update more/less then 2 rows. I try execute the following scripts many times for debug.
The results are not always only two records. If I remove the order by newid(), the number of output result will be fine. It seems like the problem in newid(). How can I solve this problem? Thanks
select *
from Products as a
where name = 'A'
and id in (
select top 2 id
from Products as b
where a.name = b.name
order by newid()
)
You can try this:
UPDATE U SET DefaultImageId = 1
FROM(
SELECT TOP 2 * FROM dbo.Products WHERE Name = 'A' ORDER BY NEWID()
) AS U
However if you filter out the DefaultImageId=1 in inner query, it would be even better too. You should note that in this case, the inner query might produce less than 2 records.
UPDATE U SET DefaultImageId = 1
FROM(
SELECT TOP 2 * FROM dbo.Products WHERE Name = 'A' AND DefaultImageId <> 1 ORDER BY NEWID()
) AS U
I think you're just looking for a simple JOIN as
UPDATE A
SET DefaultImageId = 1
FROM Products A
JOIN
(
SELECT TOP 2 Id, Name
FROM Products B
ORDER BY NEWID()
) B ON A.Id = B.Id AND A.Name = B.Name;
Demo
SQL SERVER BUG:
I think you just hit the following SQL server bug, that is still under review since 2018.
https://feedback.azure.com/forums/908035-sql-server/suggestions/33272404-cte-containing-top-and-newid-producing-incorrect
WORK AROUND:
The only thing that seems to work, based on my stesting, is if you eliminate the outside reference from the subquery, things works as expected. You can eliminate the outside reference by doing any of the following as suggested by others here.
Option 1: Keeping the query as-is, except hard-coding the filter criteria inside the subquery instead of using an outside reference:
SELECT ...
FROM t1
WHERE
t1.id IN (SELECT TOP 2 id subquery with NO outside reference WHERE name = 'A' ORDER BY ORDER BY newid() )
AND t1.name = 'A'
....
Option 2: Using a JOIN with proper ON matching criteria instead of using an outside reference inside the subquery:
SELECT ...
FROM t1
INNER JOIN (SELECT TOP 2 id subquery with NO outside reference ORDER BY newid() ) t2 ON t1.id = t2.id and t1.name = t2.name
WHERE
t1.name = 'A'
....
OR
DETAILS:
Based on my testing, when all of the following are aligned, the SQL Engine returns an unpredictable result:
An outside table is referenced inside the subquery (or through CTE) as a filtering criteria
NEWID() function is used in the ORDER BY with a SELECT TOP statement (It does NOT happen with other non-deterministic functions like RAND() for example. Something specific to NEWID())
The SELECT TOP statement uses a number less than the number of records exists in that table
This seems to throw off the SQL engine. The result changes at every run: The number of records returned varies at every run between zero records and max number of records that would have been returned if SELECT TOP was not used.
The query plan does not make sense at all. See the screenshot here. TOP N returns more than it is supposed to and id IN () predicate returns random number of records (zero in this example). How could that be possible? I have no clue. Also, note that the id IN () predicate is applied before the left table scan, which shouldn't happen. I think the unreliable result has something to do with that. We'll have to wait until SQL Server team fixes the bug to be able write the queries the way you wrote.
As you are using Correlated subquery, where outer query name is referred by subquery name, you are getting different result set.
I would suggest you to use the name parameter twice to avoid this problem.
select *
from Products as a
where name='A'
and id in
(select top 2 id
from Products as b
where b.name = 'A'
order by newid())
Similarly, for update also, you change the query
update a
set DefaultImageId=1
from Products as a
where name = 'A'
and id in (
select top 2 id
from Products as b
where b.name = 'A'
order by newid()
)
Something like this
This query selects 2 rows at random.
with top_2_cte(id, [name]) as (
select top 2 id, [name]
from Products
where name='A'
order by newid())
select a.*
from Products a
join
top_2_cte ttc on a.Id=ttc.id
and a.[Name]=ttc.[name];
Update statement
;with top_2_cte(id, [name]) as (
select top 2 id, [name]
from Products
where name='A'
order by newid())
update a
set DefaultImageId=1
from Products a
join
top_2_cte ttc on a.Id=ttc.id
and a.[Name]=ttc.[name];
I'have a little question about a query.
I have to update a column from a table where there are only record of expense(integer).
I must increase the expense of 5% if the client is from a specific state, the column of the state is in a different table and the key in common is the address.
This is my query below :
UPDATE table 1 a
SET expense_vl = (
SELECT expense*1.05 FROM table 1
LEFT JOIN table2 b ON b.ADDRESS_ID=a.ADDRESS_ID
WHERE description_state IN 'lollyland'
)
I'd recommend using a semi-join:
update table_1 a
set expense_v1 = expense * 1.05
where exists (
select null
from table2 b
where
a.address_id = b.address_id and
b.description_state = 'lollyland'
)
Althought I must add that it would help if you include the DDL for your table. We're sort of guessing at which table "description" came from.
Also, when possible, include sample input for each table and desired output. We don't need a million records, just an example that illustrates your issue.
Try below
UPDATE table1 a SET expense_vl = (SELECT expense*1.05
FROM table2 b
WHERE b.ADDRESS_ID=a.ADDRESS_ID)
WHERE description_state IN 'lollyland'
Or try with subselect:
UPDATE table1
SET expense_vl = expense*1.05
WHERE ADDRESS_ID IN (SELECT ADDRESS_ID FROM table2 WHERE description_state IN 'lollyland')
I think you need to change your query like below :
UPDATE table 1 A
SET expense_vl=expense*1.05 FROM table 1
LEFT JOIN table2 B ON B.ADDRESS_ID=A.ADDRESS_ID
WHERE B.description_state IN 'lollyland'
I'm a serious SQL noob so any help is appreciated. I'm having a hard time even explaining what I'm trying to do so I'll lay out what I have so far:
DECLARE #UserIDInt table (ID int);
INSERT into #UserIDInt
SELECT UserId
FROM [LcsCDR].[dbo].[Users]
WHERE [LcsCDR].[dbo].[Users].[UserUri] LIKE '%example';
SELECT *
FROM [LcsCDR].[dbo].[SessionDetails]
WHERE [LcsCDR].[dbo].[SessionDetails].[User1Id] = #UserIDInt;
"DECLARE #UserIDInt table (ID int);"
This creates my variable with a column called "ID"
INSERT into #UserIDInt
SELECT UserId
FROM [LcsCDR].[dbo].[Users]
WHERE [LcsCDR].[dbo].[Users].[UserUri] LIKE '%example';
This adds numeric values into the ID column based on whether or not the WHERE statement matched
SELECT *
FROM [LcsCDR].[dbo].[SessionDetails]
WHERE [LcsCDR].[dbo].[SessionDetails].[User1Id] = #UserIDInt;
This is where I am lost. I am trying to return all rows from [LcsCDR].[dbo].[SessionDetails] if the column [LcsCDR].[dbo].[SessionDetails].[User1Id] matches anything in my variable. The problem (I think) I'm having is that SQL can't look within the variable's column to find multiple values. Basically, the ID column in my variable #UserIDInt will contain a bunch of numeric values.
How do I perform the final SELECT statement and have SQL return all results if [LcsCDR].[dbo].[SessionDetails].[User1Id] matches anything within my #UserIDInt.ID column?
I am using SQL Server 2014.
Apologies if I explained it badly. Not sure how else to ask the question :)
using inner join:
select sd.*
from [lcscdr].[dbo].[sessiondetails] sd
inner join #useridint i
on i.id = sd.user1id;
or using exists():
select sd.*
from [lcscdr].[dbo].[sessiondetails] sd
where exists (
select 1
from #useridint i
where i.id = sd.user1id
);
or using in():
select sd.*
from [lcscdr].[dbo].[sessiondetails] sd
where sd.user1id in (
select id
from #useridint i
);
rextester demo: http://rextester.com/UVCB28056
Use EXISTS:
SELECT T1.*
FROM [lcscdr].[dbo].[sessiondetails] T1 WHERE EXISTS (
SELECT 1
FROM #useridint T2
WHERE T2.id = T1.user1id
);
I am trying to do an update and i'm having problems (using microsoft sql server)
update mytable
set myvalue=
(
(select myvalue from someothertable
where someothertable.id=mytable.id)
)
from table mytable
where mytable.custname='test'
Basically the subquery could return no results if that does happen i want to call a different subquery:
(select myvalue from oldtable
where oldtable.id=mytable.id)
well, you could run the second query first, and then, the first query.
In that way, you will override the values only when the first query can bring them, and when the (original) first query won't bring any result, they will have the result of first query.
Also, I think you have a typo in your second query with the table name.
update mytable
set myvalue=
(
select myvalue from oldtable
where oldtable.id=mytable.id
)
from table mytable
where mytable.custname='test'
and exists (select 1 from oldtable
where oldtable.id=mytable.id)
update mytable
set myvalue=
(
select myvalue from someothertable
where someothertable.id=mytable.id
)
from table mytable
where mytable.custname='test'
and exists ( select 1 from someothertable
where someothertable.id=mytable.id)
edit: you will need to add the exists clause, cause if not it will update with null values, I think
You can simply join both tables,
UPDATE a
SET a.myValue = b.myValue
FROM myTable a
INNER JOIN someOtherTable b
ON a.ID = b.ID
WHERE a.CustName = 'test'
Inserting in one common table with the different scenarios
E.g:
if exists(select id from tablename where id =1 )
insert into Temp
select * from tbl inner join ........
else if exists(select id from tablename where id=2)
insert into Temp
select * from tb2 inner join ........
else if exists(select id from tablename where id=3 )
insert into Temp
select * from tb3 inner join ........
....
it is like using else condition for joining different tables for different id's...
now i want to write a single query without this else if,else if... but based on the id value the respective select statement should be called
Perhaps you're looking to define a query (or view) using SELECT, WHERE, and UNION ALL. Consult the documentation (postgreSQL, MySQL, or whatever SQL dialect) for details.