How to import values into a column from another table in Access - sql

I created an Access Database and I wish to import a subset of data from a master table into a smaller table using SQL Queries. Basically, I want the smaller (Customer) table to reflect any changes made in the bigger (Total) table.
I tried the following code:
UPDATE Customer SET Brand =
(SELECT Brand FROM Total WHERE Chance = -1) ; Chance is a binary column
WHERE EXIST (SELECT Brand FROM Total WHERE Chance = -1);
, but I get an error: "operation must use an updateable query" and my file is not a read-only file.
Is there another Query that I can use to perform the same task?

Update statement in MS Access database should looks like:
UPDATE Customer AS C
INNER JOIN Total AS T ON T.PK = C.FK
SET C.Brand = T.Brand
WHERE T.Chance=-1;
Where:
PK = Primary Key
FK = Foreign Key

Related

SQL Server, updating item quantities of new items that are replacing old items

I have a CSV with two columns OldItem and NewItem; each column holds a list of integers. Note - the CSV will hold around 1,000 rows.
OldItem | NewItem
-----------------
1021669 | 1167467
1021680 | 1167468
1021712 | 1167466
1049043 | 1000062
We have old items in the system that are being replaced by the new items and we would like to capture the current quantity of the first OldItem and assign it to the first NewItem, quantity of second OldItem assigned to quantity of third OldItem, etc.
The other fun part of the issue is that the Item Numbers that are in the spreadsheet don't match up to the item numbers associated with the quantities, there's a translation table in the system called Alias.
Here are the tables and columns we're interacting with:
table Alias (essentially a translation table)
column Alias (the numbers in the spreadsheet)
column ItemID (the numbers in table "Items" that hold the quantities)
table Items (this holds all the items, new and old)
column ItemID
column Quantity
The only way I can think of doing this is doing a foreach on every OldItem like this, pseudo-code incoming:
foreach OldItem (Select Alias.ItemID WHERE Alias.Alias = OldItem)
then somehow, as I don't know how to return and use that result in SQL:
Select Item.Quantity where Item.ItemID = Alias.ItemID.
At this point I have the quantity that I want, now I have to reference back to the CSV, find the NewItem associated with the OldItem, and do this all over again with the NewItem and then update the NewItem Quantity to the one I found from the OldItem.
-dizzy-
Please help, I could solve this problem by wrapping SQL in PowerShell to handle the logical bits but it has severe performance consequences and I have to do this on MANY databases remotely with very bad network connections!
Given that you have connectivity issues, I suggest the following:
Create a working table in your database
Import your CSV into the working table
Run a script that copies aliases and quantities into the working table. Not required but helps with auditing
Run a script that validates the data
Run a script that copies required data into Items
It's important to note that this assumes that olditems are unique, and only ever map to one new item. There is a checks in the 'testing section' for that
Create a working table
Open SQL Server Management Studio and run this script in your database (choose it in the dropdown)
-- Create a schema to hold working tables that aren't required by the application
CREATE SCHEMA adm;
-- Now create a table in this schema
IF EXISTS (SELECT * FROM sys.objects WHERE name = 'ItemTransfer'
AND type = 'U'
AND schema_id = SCHEMA_ID('adm'))
DROP TABLE adm.ItemTransfer;
CREATE TABLE adm.ItemTransfer (
OldItem INT NOT NULL,
NewItem INT NOT NULL,
OldAlias VARCHAR(50) NULL,
NewAlias VARCHAR(50) NULL,
OldQuantity NUMERIC(19,2) NULL
);
Import the CSV data
There are a number of ways to do this. Your constraint is your unreliable network, and how comfortable you are troubleshooting unfamiliar tools. Here is one method that can be rerun without causing duplicates:
Open your CSV in excel and paste this monstrosity into in column 3, row 2:
="INSERT INTO adm.ItemTransfer (OldItem, NewItem) SELECT " & A2 & "," & B2 & " WHERE NOT EXISTS (SELECT * FROM adm.ItemTransfer WHERE OldItem=" & A2 & " AND NewItem=" & B2 & ");"
This will generate an insert statement for that data. Drag it down to generate all insert statements. There will be a bunch of lines that look something like this:
INSERT INTO adm.ItemTransfer (OldItem, NewItem) SELECT 1,2 WHERE NOT EXISTS (SELECT * FROM adm.ItemTransfer WHERE OldItem=1 AND NewItem=2);
Copy/paste this string of inserts into SQL Server Management Studio and run it. It should insert all of the data into your working table.
I also suggest that you save this file to a .SQL file. This insert statement only inserts if the record isn't already there, so it can be rerun.
Note: There are many ways to import data into SQL Server. the next easiest way is to right click on the database / tasks / import flat file, but it's more complicated to stop duplicates / restarting import
Now you can run SELECT * FROM adm.ItemTransfer and you should see all of your records
Map Alias and Qty
This step can actually be done on the fly but lets just write them into the working table as it will allow us to audit afterwards
These two scripts copy the alias into the working table:
UPDATE adm.ItemTransfer
SET OldAlias = SRC.Alias
FROM
adm.ItemTransfer TGT
INNER JOIN
Alias SRC
ON TGT.OldItem = SRC.ItemID;
UPDATE adm.ItemTransfer
SET NewAlias = SRC.Alias
FROM
adm.ItemTransfer TGT
INNER JOIN
Alias SRC
ON TGT.NewItem = SRC.ItemID;
This one copies in the old item quantity
UPDATE adm.ItemTransfer
SET OldQuantity = SRC.Quantity
FROM
adm.ItemTransfer TGT
INNER JOIN
Items SRC
ON TGT.OldAlias = SRC.ItemID;
After these steps, again run the select statement to inspect.
Pre update check
Before you actually do the update you should check data consistency
Count of records in the staging table:
SELECT
COUNT(*) AS TableCount,
COUNT(DISTINCT OldAlias) UniqueOldAlias,
COUNT(DISTINCT NewAlias) UniqueNewAlias,
FROM adm.ItemTransfer
The numbers should all be the same and should match the CSV record count. If not you have a problem as you are missing records or you are not mapping one to one
This select shows you old items missing an alias:
SELECT * FROM adm.ItemTransfer WHERE OldAlias IS NULL
This select shows you new items missing an alias:
SELECT * FROM adm.ItemTransfer WHERE NewAlias IS NULL
This select shows you old items missing from the item table
SELECT *
FROM adm.ItemTransfer T
WHERE NOT EXISTS (
SELECT * FROM Items I WHERE I.ItemID = T.OldItem)
This select shows you new items missing from the item table
SELECT *
FROM adm.ItemTransfer T
WHERE NOT EXISTS (
SELECT * FROM Items I WHERE I.ItemID = T.NewItem)
Backup the table and do the update
First backup the table inside the database like this:
SELECT *
INTO adm.Items_<dateandtime>
FROM Items
This script makes a copy of the Items table before you update it. You can delete it later if you like
The actual update is pretty simple because we worked it all out in the working table beforehand:
UPDATE Items
SET Quantity = SRC.OldQuantity
FROM Items TGT
INNER JOIN
adm.ItemTransfer SRC
ON SRC.NewAlias = TGT.ItemID;
Summary
All of this can be bundled up into a script and automated if required. As is, you should save all working files to a SQL file, as well as the outputs from the SELECT test statements

updating values of a table from another table through a join changes all values to 1 single value

I have 3 tables: raw_sales, sales and details. raw_sales is being populated using COPY from a txt file. All the fields in raw_sales are either string or text. After importing, we run an sql to populate sales and details. There is a foreign key (sale_id) in details. Here's a sample INSERT command that we use to populate sales and details.
INSERT INTO sales (source, source_identifier)
(SELECT DISTINCT
'FOO' AS source,
"identifier" AS source_identifier
FROM raw_sales
LEFT JOIN sales
ON sales.source_identifier = raw_sales.identifier
AND sales.source = 'FOO'
WHERE sales.id IS NULL
AND identifier IS NOT NULL);
INSERT INTO details (sale_id, description)
(SELECT DISTINCT
sales.id AS sale_id,
"improvements" as description
FROM raw_sales
JOIN sales
ON sales.source_identifier = raw_sales.identifier
AND sales.source = 'FOO'
LEFT JOIN details AS existing
ON existing.sale_id = sales.id
WHERE existing.id IS NULL
AND "improvements" != '');
This seems to work fine. After this, there's another sql that's being ran to update existing tables. The query is as follows
UPDATE details SET
description = "improvements"
FROM raw_sales
JOIN sales
ON sales.source_identifier = raw_sales.identifier
AND sales.source = 'FOO'
JOIN details AS existing
ON existing.sale_id = sales.id
WHERE existing.id IS NOT NULL;
This query updates all rows in the details table to a single value, the first non-empty value from raw_sales table. How can I change the above sql so that it updates the existing records in the details table?
There are several problems with your query:
if details.id is a primary key (field id typically is), then what is the point in comparing it to NOT NULL? You're not using any left joins, there is no way it could possibly be NULL if it truly is an identifier.
UPDATE table t SET ... FROM ... requires linking the table t with something on the FROM section, but you're not, therefore each row of table will be updated to any single random row from the FROM results.
Perhaps you want to do this:
UPDATE details SET
description = "improvements"
FROM raw_sales
JOIN sales ON (sales.source_identifier = raw_sales.identifier AND sales.source = 'FOO')
JOIN details AS existing ON (existing.sale_id = sales.id)
WHERE existing.id = details.id;

Deleting value using SQlite while doing an INNER JOIN

I am trying to delete all voters from a voters table where they are not registered as a democrat or republican AND only voted once. I have a database with three tables, congress_members, voters, and votes and have to JOIN votes with voters in order to delete the right data.
This code finds the data I want to delete:
SELECT voters.*
FROM voters JOIN votes ON voters.id = votes.voter_id
WHERE party = 'green' OR party = 'na' OR party = 'independent'
GROUP BY votes.voter_id
HAVING COUNT(*) = 1;
But I am unable to delete it because I am getting an error everytime I try to delete with a JOIN statement
You can phrase this as a delete with a where clause:
delete from voters
where votes.party not in ('democrat', 'republican') and
voters.id in (select id from votes group by id having count(*) = 1);
You are getting the error because the join will query your database and create a temporary table that will hold your newly queried data. The delete staements are used to remove data that is stored inside your database on your disk and not inside your memory.
The delete statement syntax is "DELETE FROM table WHERE conditions". The table value will need to be one of the three tables in your database, and your target is voters. As of right now, you have half of your delete statement complete.
The where clause needs to evaluate to a boolean value for each row. There is a function called EXISTS (). This function can be used to delete this data. Essentially, you will place your select statement from your post inside of the EXISTS (). The function will compare each of your rows in the target delete table to a row in your table inside of exists. If there is a match, then the row exists, the function evaluates to true for that row, and it is deleted.
DELETE FROM voters
WHERE (party = 'green' OR party = 'na' OR party = 'independent')
AND EXISTS (
SELECT 1 FROM votes WHERE votes.id = voters.id
HAVING COUNT(*) = 1
)

SQL Update from one table to another, and in some instances creating a new record where data doesnt exist

I have imported some data into a new sql table and have managed to update the imported data into the correct table but its unable to update for records without a customer number, i have tried updating the customer number but it says it cant update a primary key record.
This is the code i used to update the fields so far...
update SalBudgetCust
Set
SalBudgetCust.Sales1 = SalBudgetCust_temp.Sales1,
SalBudgetCust.Sales2 = SalBudgetCust_temp.Sales2,
SalBudgetCust.Sales3 = SalBudgetCust_temp.Sales3,
SalBudgetCust.Sales4 = SalBudgetCust_temp.Sales4,
SalBudgetCust.Sales5 = SalBudgetCust_temp.Sales5,
SalBudgetCust.Sales6 = SalBudgetCust_temp.Sales6,
SalBudgetCust.Sales7 = SalBudgetCust_temp.Sales7,
SalBudgetCust.Sales8 = SalBudgetCust_temp.Sales8,
SalBudgetCust.Sales9 = SalBudgetCust_temp.Sales9,
SalBudgetCust.Sales10 = SalBudgetCust_temp.Sales10,
SalBudgetCust.Sales11 = SalBudgetCust_temp.Sales11,
SalBudgetCust.Sales12 = SalBudgetCust_temp.Sales12
From
SalBudgetCust_temp where SalBudgetCust.Customer = SalBudgetCust_temp.Customer
Would anyone be able to offer some light on how if the customer record doesnt exist already it populates from the other table and then includes the corresponding sales figures?
Try SELECT INTO statement as below for inserting records where customer doesnt exist:
SELECT * INTO SalBudgetCust FROM SalBudgetCust_temp WHERE NOT EXISTS (SELECT Customer FROM SalBudgetCust WHERE Customer = SalBudgetCust_temp.Customer)
This SO Answer might also help you to the solution:
How to avoid duplicates in INSERT INTO SELECT query in SQL Server?

Updating a table by referencing another table

I have a table CustPurchase (name, purchase) and another table CustID (id, name).
I altered the CustPurchase table to have an id field. Now, I want to populate this newly created field by referencing the customer ids from the CustID table, using:
UPDATE CustPurchase
SET CustPurchase.id = CustID.id
WHERE CustPurchase.name = CustID.name;
I keep getting syntax errors!
I believe you are after the useful UPDATE FROM syntax.
UPDATE CustPurchase SET id = CI.id
FROM
CustPurchase CP
inner join CustID CI on (CI.name = CP.name)
This might have to be the following:
UPDATE CustPurchase SET id = CI.id
FROM
CustID CI
WHERE
CI.name = CustPurchase.name
Sorry, I'm away from my Postgres machine; however, based upon the reference, it looks like this is allowable. The trouble is whether or not to include the source table in the from_list.
Joining by name is not an ideal choice, but this should work:
UPDATE custpurchase
SET id = (SELECT c.id
FROM CUSTID c
WHERE c.name = custpurchase.name)
The caveat is that if there's no match, the value attempting to be inserted would be NULL. Assuming the id column won't allow NULL but will allow duplicate values:
UPDATE custpurchase
SET id = (SELECT COALESCE(c.id, -99)
FROM CUSTID c
WHERE c.name = custpurchase.name)
COALESCE will return the first non-NULL value. Making this a value outside of what you'd normally expect will make it easier to isolate such records & deal with appropriately.
Otherwise, you'll have to do the updating "by hand", on a name by name basis, to correct instances that SQL could not.