UPDATE with multiple values from subquery - sql

Suppose I have a table, items, with an integer column named priority, which I'm trying to update from another table. (This other table is a temporary table, where I've pre-calculated all of the appopriate priority values to be applied.)
UPDATE "items" SET "priority" = (
SELECT "newPriority" FROM "newPriorities"
);
What ends up happening is that all entries in items have their priority set to the first value returned from the newPriorities sub-query.
How can I set priority to be different for each record? To put it another way, how can I update items to have all of the correct priority values from the newPriorities table?
Sample Data
items
id priority /* some other, unreleated columns */
2108f97e-e1ce-47bf-97fd-c20699d2aa27 0
fae2347c-8644-47ba-931f-3d3cf70d3565 1
bd5ed046-47fa-49d9-9b40-2aa920511cf2 3
1fc57417-93e1-4382-8246-c4f9d117a55a 4
2ab4afbc-aa56-45af-8509-a7d9377e689d 5
7407a3a5-d410-4190-81c8-54d672f22c8d 6
1b21b57e-e907-4c25-af00-94bbf941df63 7
newPriorities
id newPriority
2108f97e-e1ce-47bf-97fd-c20699d2aa27 15
fae2347c-8644-47ba-931f-3d3cf70d3565 22
bd5ed046-47fa-49d9-9b40-2aa920511cf2 554
1fc57417-93e1-4382-8246-c4f9d117a55a 8
2ab4afbc-aa56-45af-8509-a7d9377e689d 3
7407a3a5-d410-4190-81c8-54d672f22c8d 6
1b21b57e-e907-4c25-af00-94bbf941df63 743
Desired Result: newPriority column values copied to items.

You seem to want:
UPDATE "items" as i
SET "priority" = (SELECT "newPriority"
FROM "newPriorities" np
WHERE np.id = i.id
);

Related

How can I get the last row without order by and assign a value to a variable?

I have a query that is within a View so I can not use order by . I have a column called Course that column is an Int Column and it can have many repeating values . There is also a column called status that status column is also an Int and it will have unique values . I am trying to create a query where we can get the last row of a particular Course and see if the Status is 2 if yes then add 1 to #MyValue if not then add 0 to the variable .I have an ID column which is the primary key, without order by I am having a tough time figuring this one out .
MyValue is a smallint and we simply assign the value
CourseNumber is a Int and a table can have many (Course) #CourseNumber with the same number
There will only be 1 combination of CourseNumber and Status . We can have many CourseNumbers with the same number etc 120 however each one will have a different Status
What I want to do with the query below is get the last record of #CourseNumber we have an ID column and check if the status of the last record of #CourseNumber is equal to 2 . If it's equal to 2 then assign the value 1 to #MyValue and if it is not equal to 2 then assign the value 0 .
SELECT #MyValue =(SELECT count(*) FROM MyTasks as MT WHERE MT.Course = #CourseNumber And MT.status=2)
Sample: ID Course Status
1 23 4
2 23 5
3 23 2
4 23 1
Assuming that was the database table the Course is [#CourseNumber] is 23 . We would want to get the last row of the Course number which is [4] and we would want the status which is [1] since the status is not 2 for that last row we would just return a 0 and we would only return a 1 if the last row of the course number has a status of 1 . This is a sql function inside of a view . I try to leave out some of things that might not be necessary since it is a large View and function .
You want to self join to the table to determine the maximum ID value to find the record you want. You say add 1 to #MyValue and later you say to set #MyValue = 1. This will add 1 to #MyValue. If you want #MyValue = 1, change the case statement removing the #MyValue parameter.
DECLARE #MyValue INT = 0
, #CourseNumber INT = 23
SELECT #MyValue = CASE WHEN t0.Status = 2 THEN #MyValue + 1 ELSE #MyValue END
FROM MyTasks t0
JOIN
(
SELECT Couse
, MAX(ID) MAXID
FROM MyTasks
WHERE Course = #CourseNumber
) t1 ON t0.Course = t1.Course AND t0.ID = t1.MAXID

SQL - Update top n records for each value in column a where n = count of column b

I have one table with the following columns and sample values:
[test]
ID | Sample | Org | EmployeeNumber
1 100 6513241
2 200 3216542
3 300 5649841
4 100 9879871
5 200 6546548
6 100 1116594
My example count query based on [test] returns these sample values grouped by Org:
Org | Count of EmployeeNumber
100 3
200 2
300 1
My question is can I use this count to update test.Sample to 'x' for the top 3 records of Org 100, the top 2 records of Org 200, and the top 1 record of Org 300? It does not matter which records are updated, as long as the number of records updated for the Org = the count of EmployeeNumber.
I realize that I could just update all records in this example but I have 175 Orgs and 900,000 records and my real count query includes an iif that only returns a partial count based on other columns.
The db that I am taking over uses a recordset and loop to update. I am trying to write this in one SQL update statement. I have tried several variations of nested select statements but can't quite figure it out. Any help would save my brain from exploding. Thanks!
Assuming, that id is the unique ID of the row, you could use a correlated subquery to select the count of row IDs of the rows sharing the current organization, that are less than or equal to the current row ID and check, that this count is less than or equal to the number of records from that organization you want to designate.
For example to mark 3 records of the organization 100 you could use:
UPDATE test
SET sample = 'x'
WHERE org = 100
AND (SELECT count(*)
FROM test t
WHERE t.org = test.org
AND t.id <= test.id) <= 3;
And analog for the other cases.
(Disclaimer: I don't have access to Access (ha, ha, pun), so I could not test it. But I guess it's basic enough, to work in almost every DBMS, also in Access.)

How do I display grouped ID's as a list with their respective values?

How do I not get all the ID's grouped, but instead listed from first to last; with all their respective values in the columns next to them?
Instead of grouping it, it should show ID 1 and its value, ID 2 and its value. EVEN if the values for the ID is the same. I tried removing the GROUP_CONCAT, but then it's only showing one ID per customfield_value?
SELECT GROUP_CONCAT(virtuemart_product_id), customfield_value, COUNT(*) c
FROM jos_virtuemart_product_customfields
WHERE virtuemart_custom_id = 6
GROUP BY customfield_value
HAVING c > 1
It's working currently, but grouping the ID's and spacing them with a comma. Should just display as in a normal table/list format.
Currently it shows like this(as you can see, it's ALL the same ICOS number, but different ID's. I ONLY need to display the values WHERE the ICOS NUMBER is "duplicate"):
ID ICOS Count
1,2,3 775896 3
It should be displaying like this:
ID ICOS Count
1 775896 1
2 775896 1
3 775896 1
All rows where the customfield_value is not unique:
-- Assuming MySQL
SELECT virtuemart_product_id, customfield_value
, COUNT(*) c -- maybe not needed
FROM jos_virtuemart_product_customfields
WHERE virtuemart_custom_id = 6
AND customfield_value IN
( SELECT customfield_value
FROM jos_virtuemart_product_customfields
WHERE virtuemart_custom_id = 6
GROUP BY customfield_value
HAVING COUNT(*) > 1 -- more than one row exists
)
GROUP BY virtuemart_product_id, customfield_value -- maybe not needed
If the virtuemart_product_id is unique you don't need the outer count/group by as it will always be 1.

SQL query to pull certain rows based on values in other rows in the same table

I have a set of data that contains 2 sets of identifiers: a unique number for that record, Widget_Number, and the original unique number for the record, Original_Widget_Number. Typically these two values are identical but when a record has been revised, the a new record is created with a new Widget_Number, preserving the old Widget_Number value in Original_Widget_Number. IE SELECT * FROM widgets WHERE Widget_Number != Original_Widget_Number returns all records that have been changed. (Widget_Number increments by 10 for new widgets and by 1 for revised widgets.)
I would like to return all records that were changed as well as the original records related to those records. For example if I had a table containing:
Widget_Number Original_Widget Number More_Data
1: 10 10 Stephen
2: 11 10 Steven
3: 20 20 Joe
I would like a query to return rows 1 & 2. I know I could loop trough this in a higher-level language but is there a straightforward way to do this in MS SQL?
using exists():
select *
from widgets as t
where exists (
select 1
from widgets as i
where i.original_widget_number = t.original_widget_number
and i.widget_number != i.original_widget_number
)
or in()
select *
from widgets as t
where t.original_widget_number in (
select i.original_widget_number
from widgets as i
where i.widget_number != i.original_widget_number
)
The following should get both the records that have changed and the original records:
select w.*
from widgets w
where w.widget_number <> w.original_widget_number or
exists (select 1
from widgets w2
where w.widget_number = w2.original_widget_number and
w2.widget_number <> w2.original_widget_number
);
select * from widget
where original_widget_number in
(select original_widget_number from widget
where widget_number <> original_widget_number)

what's the difference between SQL's

I work with Databases not extensively but to the point where I can write Selects, update's ,small joins etc..
I can get my work done with my current knowledge. I have encountered some difficulty while trying to complete a task, I got the task completed but would like to understand why some of the SQL's that I have written in process did not work.
Task at hand: I have a table "TESTTABLE" that has 5 columns and the 6th is the sum of these 5 columns.
Currently table looks like below:
ID NAME SUB1 SUB2 SUB3 SUB4 SUB5 TOTAL
1 VA 10 20 30 40 50
2 MI 20 40 60 80 10
3 NC 10 30 50 70 90
4 SC 10 20 30 40 50
5 WA 20 40 60 80 15
the last column 'Total' is currently empty.
Now,I need to update the total column in the table with the sum(sub1+sub2=sub3+sub4+sub5).
In this process I have written the following SQL's and it did work, would like to understand the difference.
Attempt1:
UPDATE TESTTABLE T
SET Total =
SELECT (sub1+sub2+sub3+sub4+sub5)
FROM TESTTABLE TB
WHERE T.ID = TB.ID);
Error encountered:--ERROR: (2) This form of correlated query is not supported - consider rewriting;
Attempt2:
CREATE TABLE TEMP_TESTTABLE AS( SELECT ID, SUM(sub1+sub2+sub3+sub4+sub5) AS SUB_TOTAL FROM TESTTABLE )
UPDATE TESTTABLE A
SET TOTAL =
(SELECT SUB_TOTAL
FROM TEMP_TESTTABLE B
WHERE B.ID=A.ID);
ERROR encountered: ERROR: (2) This form of correlated query is not supported - consider rewriting
Attempt3:
UPDATE TESTTABLE
SET TOTAL = SUM(sub1+sub2+sub3+sub4+sub5);
ERROR encountered: ERROR: Aggregate functions not allowed in the set list of an UPDATE statement
Attempt4- Successful one;
UPDATE TESTTABLE A
SET TOTAL = B.SUB_TOTAL FROM TEMP_TESTTABLE B
WHERE A.ID=B.ID
Attempt 4 worked for me by using the temp table created in attempt2 [TEMP_TESTTABLE].
I need some detail explanation, and appreciate if anyone can provide me and let me know how my attempt4 is different than 1,2,3.
Help is greatly appreciated.
Thanks,
Attempt1 failed because subqueries should be enclosed in parentheses.
UPDATE TESTTABLE T
SET Total =
(SELECT (sub1+sub2+sub3+sub4+sub5)
FROM TESTTABLE TB
WHERE T.ID = TB.ID);
Attempt2 failed because SUM() function is aggregate function, to sum values from multiple rows, not to sum values from multiple columns in one row.
You should redefine the column as a computed column, like this
Alter table TESTTABLE
add column Total as sub1+sub2+sub3+sub4+sub5
This is the cannonical Soluion.
UPDATE
TESTTABLE
SET
Total = (sub1+sub2+sub3+sub4+sub5)
The reason the others failed is that you where doing subselects that returned multiple rows. You didn't tell the UPDATE how the different rows mapped from the select to the UPDATE.
In this version you are making it simple - one table - on each row set a value on that row based on the data in that row.
In your final version you're doing the same but in a redundant way (extra join that does nothing).