Not updatable query - Access - ms-access

This should be a simple query - I have read through several other posts, but can't figure out how to integrate their solutions into my query.
UPDATE Items_tbl
SET Items_tbl.ITEM_QTY_ONHAND =
(SELECT Sum([Item_Locations_tbl]![ITEMLOC_QTY_ONHAND])
FROM [Item_Locations_tbl]
WHERE Items_tbl.ITEM_ID =Item_Locations_tbl.ITEMLOC_LOC_ID);

The query is not updateable because you are using an aggregate function (specifically, sum).
You can avoid this by instead using a domain aggregate function, such as DSum, e.g.:
update items_tbl
set items_tbl.item_qty_onhand =
dsum("itemloc_qty_onhand", "item_locations_tbl", "itemloc_loc_id = " & items_tbl.item_id)
Note that the above assumes that your itemloc_loc_id field is numerical; if this field is string-valued, then you will need to surround the criteria with single-quotes, e.g.:
update items_tbl
set items_tbl.item_qty_onhand =
dsum("itemloc_qty_onhand","item_locations_tbl","itemloc_loc_id = '" & items_tbl.item_id & "'")
An alternative way to circumvent the restriction of the inability to use aggregate functions in an UPDATE query is to generate a temporary table to store the value of the sum for each record, and then update your table using the values held by the temporary table.

Related

Rails - How to reference model's own column value during update statement?

Is it possible to achieve something like this?
Suppose name and plural_name are fields of Animal's table.
Suppose pluralise_animal is a helper function which takes a string and returns its plural literal.
I cannot loop over the animal records for technical reasons.
This is just an example
Animal.update_all("plural_name = ?", pluralise_animal("I WANT THE ANIMAL NAME HERE, the `name` column's value"))
I want something similar to how you can use functions in MySQL while modifying column values. Is this out-of-scope or possible?
UPDATE animals SET plural_name = CONCAT(name, 's') -- just an example to explain what I mean by referencing a column. I'm aware of the problems in this example.
Thanks in advance
I cannot loop over the animal records for technical reasons.
Sorry, this cannot be done with this restriction.
If your pluralizing helper function is implemented in the client, then you have to fetch data values back to the client, pluralize them, and then post them back to the database.
If you want the UPDATE to run against a set of rows without fetching data values back to the client, then you must implement the pluralization logic in an SQL expression, or a stored function or something.
UPDATE statements run in the database engine. They cannot call functions in the client.
Use a ruby script to generate a SQL script that INSERTS the plural values into a temp table
File.open(filename, 'w') do |file|
file.puts "CREATE TEMPORARY TABLE pluralised_animals(id INT, plural varchar(50));"
file.puts "INSERT INTO pluralised_animals(id, plural) VALUES"
Animal.each.do |animal|
file.puts( "( #{animal.id}, #{pluralise_animal(animal.name)}),"
end
end
Note: replace the trailing comma(,) with a semicolon (;)
Then run the generated SQL script in the database to populate the temp table.
Finally run a SQL update statement in the database that joins the temp table to the main table...
UPDATE animals a
INNER JOIN pluralised_animals pa
ON a.id = pa.id
SET a.plural_name = pa.plural;

split() not working with mySQL join?

I'm currently using the mySQL common schema package along with the split() function, but I'm struggling to get a working JOIN query to work?
set #script := "
split({size:2000} :
UPDATE world
SET world.CountryName = (
SELECT country.nicename
FROM country
WHERE country.iso = world.Country
)
)
{
throttle 4;
SELECT $split_total_rowcount AS 'rows updated so far';
}
";
call common_schema.run(#script);
When running this query, it produces the following:
#1644 - QueryScript error: [split() cannot deduce split table name. Please specify explicitly] at 34: "UPDATE world
SET world.Country
As for why I'm trying to split my UPDATE query into chunks, is because it's trying to update a table that's got 3M+ rows & is struggling when doing the query on it's own
Please specify explicitly appears to refer to using this format:
Multiple tables operations; explicit declaration of splitting table:
split (schema_name.table_name: statement operating on multiple tables)
statement;
https://shlomi-noach.github.io/common_schema/query_script_split.html
See also explicit declaration.

ASP Classic recordset unable to see columns with 'table.column_name' format after MySQL conversion

I am currently in the process of converting a large amount of ASP classic/VBscript pages from an old database (Unify Dataserver) to MySQL.
Say you have a query like this:
sql = "SELECT c.container_type, c_amount, c_sdate, c_edate, csrt " & _
"FROM containers c, container_chars cc"
objRS.Open sql, objConn, 3, 1
If I want to reference the column "c_edate", I can simply use this and it works fine:
x = objRS("c_edate")
However, when it comes to referencing a column like "c.container_type" (With a . used to differentiate it from another table, like so:
x = objRS("c.container_type")
It will say
ADODB.Recordset error '800a0cc1'
Item cannot be found in the collection corresponding to the requested name or ordinal.
I can fix it by using a number instead:
objRS(0)
This was never an issue until we switched to MySQL. In our old database, using the rs(table.column_name) format worked just fine. But in MySQL, once you add a (.) to the code, it can't find that item unless you switch it to a number.
As you can imagine, this is quite a pain as I go through the 700+ pages of this website manually counting the placement of each column in the corresponding select statement every time something from the query is referenced.
Does anyone know why this is happening or how to make the rs(table.column_name) format work with MySQL like it does with our old database?
In SQL Server, and apparently in MySQL too, the way to reference a field in the result set is to just use the name, without the prefix.
x = objRS("container_type")
The prefix is needed by the database to differentiate between identically-named columns, but once you send the results to a recordset, that recordset doesn't know or care where the columns came from.
The same goes for aliases:
SQL = "SELECT c.container_type AS ctype, [...]"
...
x = objRS("ctype")
Combining these two facts, if you do have identically-named columns in the result set, you must alias at least one of them. If you don't, it won't necessarily give an error, but you will not be able to reference the second column using the rs("name") syntax.
SQL = "SELECT c1.container_type, c2.container_type AS c_type2, ..."
...
x = objRS("container_type")
y = objRS("c_type2")
[Note that while you're at it, you probably should also modify your FROM clauses to use proper FROM table1 INNER JOIN table2 ON table1.fieldA = table2.fieldB type syntax. The FROM table1, table2 WHERE table1.fieldA = table2.fieldB syntax has been deprecated for many years now.]

Using IN statement in parameterized crosstab query in Access

I have a crosstab query which queries a bunch of locations and gets their measurement readings. I pivot on the measurement readings so I get a table which has all the measurements for a location/date combo on each line. This works fine for getting all the data. It also works fine for filtering on one value per field. i.e. WHERE LocationID = ? AND MeasureID = ? but what I really need is to have something like WHERE LocationID IN (?) AND MeasureID IN (?) where ? is an array (or whatever gets to job done. Is this possible?
On my forms I'm using a DAO.QueryDef object to build my recordsets. I'd like to avoid building the entire query string in VBA if possible, mostly because this particular query is pretty long and I'd rather it live in a view and not a code module. With that said I can build it all in VBA but it's just not the desired solution.
You can always use replace.
sSQL = "SELECT lots of sql WHERE LocationID IN (qqlocidqq)"
sSQLWithLoc = Replace (sSQL, "qqlocidqq", "1,2,3,4")
Dim qdf As QueryDef
'A query that exists
Set qdf= CurrentDB.QueryDefs("MyJunkQuery")
'Permanently change the sql of that query
qdf.SQL = sSQLWithLoc
Looking into this a little further, it may suit you to use Instr, like so:
SELECT Table1.LocationID
FROM Table1
WHERE InStr([#List],[LocationID])>0
Tested like so:
PARAMETERS Number_List Text(50);
TRANSFORM Count(Table1.AKey) AS CountOfAKey
SELECT Table1.AText
FROM Table1
WHERE InStr([Number_List],[ANumber])>0
GROUP BY Table1.AText
PIVOT Table1.ANumber;
Where Table1 consists of fields AKey, AText, and ANumber. Number_List is a comma separated list of numbers supplied by a parameter. Instr checks for the existence of ANumber from Table1 in the supplied parameter.
There is a problem with overlap 1,2,12, but a creative use of commas may suit:
WHERE InStr("," & [Number_List] & "," , "," & [ANumber] & ",")>0
Of course the delimiter does not have to be a comma, | is often useful.

Efficient Update SQL, updating multiple rows with one SQL statement, Avoiding Loops

I'm trying to avoid database access in loops within a project I am working on. Not being too good with SQL, I'm not sure of the best way to approach this.
I'm updating a stock level database in a sale procedure with multiple stock locations/pick locations.
Therefore, this is what I am doing.
Looping through Product IDs, then looping through the pick locations for each product and updating quantities as it goes, like:
For Each wProductId In calculatedProds.Keys '' loop through products requested passing values of pick locations
For i = 0 To locationCount ' split the location value from the string as per above
Dim thisLocation As Integer = locationID
Dim thisQty As Integer = qtyPicked
Dim sql As String = "UPDATE `stockLevels` SET `stockLevel`=`stockLevel` - '" & thisQty & "' WHERE `stockLocation`='" & thisLocation & "' AND `id`='" & wProductId & "'"
' DO DATA ACCESS WITH SQL ABOVE
Next
Next
Of course this works, but it is opening a new Database Connection for every stock location, for every item.
So how would I work this into a single Update Statement?
http://www.karlrixon.co.uk/writing/update-multiple-rows-with-different-values-and-a-single-sql-query/
That link gets me very close to what I am after, I think, but I am not 100% sure how to dynamically build that SQL statement and how to add two conditions to the CASE.
I need to build a SQL Statement something like:
UPDATE stockLevels
SET stockLevel= CASE id
WHEN '"& wProductId &"' AND stockLocation='"& thisLocation &"' THEN `stockLevel` - '" & thisQty & "'
WHEN '"& NEXTwProductId &"' AND stockLocation='"& NEXTthisLocation &"' THEN `stockLevel` - '" & NEXTthisQty & "'
END
But that's not correct where I am adding the second parameter to the CASE!
I am using MySQL and VB.NET, as usual, any help much appreciated.
Using a case statement in the set clause in your example isn't ideal for a number of reasons.
There is no where clause to help the database execute the query efficiently
The size of the query for large numbers of updates becomes excessive (consider updating 1000 rows like this)
You are manually implementing a join - the database can almost certainly do this more efficiently than you.
Debugging such a query is also difficult.
Instead, you should first measure the performance of the update one at a time approach to see if you actually need to make improvements.
If performance improvements are required, then I would suggest an approach where the updates are first bulk inserted into a temporary table. A suitable table would have the following columns:
wProductID, stockLocation, newStockLevel
The updates can be bulk inserted using the following MySQL syntax:
INSERT INTO temp_stock_updates
(wProductID, stockLocation, newStockLevel)
VALUES
(?,?,?), (?,?,?), (?,?,?), ...
And then a single update is run to update the main table. This query would look something like this:
UPDATE stockLevels s
JOIN temp_stock_updates u USING (wProductID, stockLocation)
SET
s.stockLevel = u.newStockLevel
Your CASE expression is simply incorrect syntactically.
There are two kinds of CASE expressions, almost identical to each other and yet slightly different in syntax.
One has the form of
CASE expr
WHEN value1 THEN result1
WHEN value2 THEN result2
...
ELSE result_else
END
The other looks like this:
CASE
WHEN condition1 THEN result1
WHEN condition2 THEN result2
...
ELSE result_else
END
And you were essentially attempting to mix these two kinds of CASE.
You probably just need to use the second one (also called search CASE, if I am not much mistaken):
...
CASE
WHEN id = '"& wProductId &"' AND stockLocation='"& thisLocation &"' THEN ...
WHEN id = '"& NEXTwProductId &"' AND stockLocation='"& NEXTthisLocation &"' THEN ...
...
Note that if there's no match and the CASE has no ELSE part, the result will be NULL, so make sure you've covered all the cases, otherwise use an ELSE part like this:
ELSE `stocklevel`
I.e. the CASE will evaluate to the original value of the column being updated, rendering no update for it in the end.