Is there a way to include a query that is non updateable in an UPDATE query? [duplicate] - sql

This question already has an answer here:
Access SQL Update One Table In Join Based on Value in Same Table
(1 answer)
Closed 10 years ago.
For the following query:
UPDATE tempSpring_ASN AS t
SET t.RECORD_TYPE = (
SELECT TOP 1 RECORD_TYPE
FROM (
SELECT "A" AS RECORD_TYPE
FROM TABLE5
UNION ALL
SELECT "B" AS RECORD_TYPE
FROM TABLE5
)
);
I'm getting, "Operation must use an updateable query." I don't understand. I'm not trying to update a union query. I'm just trying to update an otherwise updatable recordset with the output (single value) of a union query.
(The solution provided at Access SQL Update One Table In Join Based on Value in Same Table (which is also provided below) does not work for this situation, contrary to what is indicated on the top of this page.)

This question is a reference to a previous question, data and code examples posted here:
Access SQL Update One Table In Join Based on Value in Same Table
Hi AYS,
In Access, an Update query needs to be run on a table.
As a UNION query is a combination of multiple sets of records, the result set is no longer a table, and cannot be the object of an Update query as the records in the result set are no longer uniquely identified with any one particular table (even if they theoretically could be). Access is hard-coded to treat every UNION query as read-only, which makes sense when there are multiple underlying tables. There are a number of other conditions (such as a sub-query in the SELECT statement) that also trigger this condition.
Think if it this way: if you were not using TOP 1 and your UNION query returned multiple results, how would JET know which result to apply to the unique record in your table? As such, JET treats all such cases the same.
Unfortunately, this is the case even when all of the data is being derived from the same table. In this case, it is likely that the JET optimizer is simply not smart enough to realize that this is the case and re-phrase the query in a manner that does not use UNION.
In this case, you can still get what you want by re-stating your query in such a way that everything references your base table. For example, you can use the following as a SELECT query to get the PO_NUM value of the previous SHP_CUSTOM_5 record:
SELECT
t1.SHP_CUSTOM_5
, t1.PO_NUM
, t1.SHP_CUSTOM_5 -1 AS PREV_RECORD
, (SELECT
t2.PO_NUM
FROM
tempSpring_ASN As t2
WHERE
t2.SHP_CUSTOM_5 = (t1.SHP_CUSTOM_5 -1)
) AS PREV_PO
FROM
tempSpring_ASN AS t1
;
You can then phrase this as an Update query as follows in order to perform the "LIN" updates:
UPDATE
tempSpring_ASN AS t1
SET
t1.RECORD_TYPE = "LIN"
WHERE
t1.PO_NUM=
(
SELECT
t2.PO_NUM
FROM
tempSpring_ASN As t2
WHERE
t2.SHP_CUSTOM_5 = (t1.SHP_CUSTOM_5 -1)
)
;
This code was successful in the tests I ran with dummy data.
Regarding your "HDR" updates, your are really performing two separate updates.
1) If the PO_NUM matches the previous record's PO_NUM, set RECORD_TYPE to "LIN"
2) If it is the first record, set RECORD_TYPE to "HDR"
It is not clear to me why there would be a benefit to performing these actions within one query. I would recommend performing the HDR update using the "TOP 1" by SHP_CUSTOM_5 method you used in your original SELECT query example, as this will be a relatively simple UPDATE query. It is possible to use IIF() within an Update query, but I do not know what additional benefit you would gain from the additional time and complexity that would be required (it would most likely only be much less readable).
Best of luck!

Related

PostgreSQL: Inserting into one table then updating another using the same subquery, within the same single query

I have a fairly intricate query and I am finding it difficult to create the result of updating two different tables from the same subquery in the FROM. The difficulty I am facing is suggesting I have attempted the incorrect flow:
Below is an extremely simplified version of the script I have working for updating table1 from the subquery:
UPDATE
table1
SET
columnX= subquery.column2
FROM
(
SELECT column1, column2, column2
FROM table2
) AS subquery
WHERE subquery.column1 = table1.column1;
Now I need to bring a third table (table3) into the mix and map table2(subquery).column2 to a value on INSERT.
I cannot do this using a second query which would be ideal as the subquery generates UUID's that must persist across the table1.columnX and table3.column1.
Can I include the INSERT within the subquery whilst still returning the same subquery table?
INSERT...RETURNING uuid_column_name may be the magic you need in your subquery.
https://www.postgresql.org/docs/13/sql-insert.html

Postgres: select for update using CTE

I always had a query in the form of:
UPDATE
users
SET
col = 1
WHERE
user_id IN (
SELECT
user_id
FROM
users
WHERE
...
LIMIT 1
FOR UPDATE
);
And I was pretty sure that it generates a lock on the affected row until the update is done.
Now I wrote the same query using CTE and doing
WITH query AS (
select
user_id
FROM
users
WHERE
...
LIMIT 1
FOR UPDATE
)
UPDATE
users
SET
col = 1
WHERE
user_id IN (
SELECT
user_id
FROM
query
);
I’m actually having some doubts that it is applying a row lock because of the results I get, but I couldn’t find anything documented about this.
Can someone make it clear? Thanks
Edit:
I managed to find this:
If specific tables are named in FOR UPDATE or FOR SHARE, then only rows coming from those tables are locked; any other tables used in the SELECT are simply read as usual. A FOR UPDATE or FOR SHARE clause without a table list affects all tables used in the statement. If FOR UPDATE or FOR SHARE is applied to a view or sub-query, it affects all tables used in the view or sub-query. However, FOR UPDATE/FOR SHARE do not apply to WITH queries referenced by the primary query. If you want row locking to occur within a WITH query, specify FOR UPDATE or FOR SHARE within the WITH query.
https://www.postgresql.org/docs/9.0/sql-select.html#SQL-FOR-UPDATE-SHARE
So I guess it should work only if the for update is in the with and not in the query that is using the with?

Flagging records that meet a specific condition using SQL on a Firebird Database

I am currently working with a Firebird database and I am trying to identify/flag records
that have a zero pos_buildcount value and where the previous record to the zero record has a pos_buildcount value that is not 255. I can do it in excel but I want to do it in a SQL query as excel can only deal with a certain amount of records. Essentially I want my results to look like the following image:
I have tried the following links to try select individual records but most solutions use a id number which my database doesn't have (I don't know why) or the solutions use the row_number() command which Firebird does not have.
Selecting the last record that meets a condition
Is there a way to access the “previous row” value in a SELECT statement?
use a id number which my database doesn't have
Then add it.
SQL is a language of sets: https://en.wikipedia.org/wiki/Set_(mathematics)
By definition, elements in the set are not located left or right to one another, to the North or to the South, or before and after. They just exists. In unordered way.
So, if you want your rows ordered - then you have to ADD some ordering value (field, column) into it, and then populate that value. And then reading from the table, if you want it, you may ask to order the results by that value.
As of now, Firebird has all the rights to read rows in any order it might like, even to change the order of the rows on disc (it will not, but that is implementation ndetail and it may change in future).
You have to add some ID column and then to populate it.
This would make "last record" or "prior record" or "row above" meaningful idioms: "object with ID one less than ID of current object". As of now in SQL terms there is no any meaning in "last record" and reliable formulating a query is not possible.
After that changing the flag column in the table becomes a trivial MERGE statement.
MERGE INTO MyTable T1
USING MyTable T2
ON (T2.ID = T1.ID - 1) AND (T2.pos_buildcount <> 255)
WHEN MATCHED THEN
UPDATE SET T1.flag = 1
http://www.firebirdsql.org/file/documentation/reference_manuals/fblangref25-en/html/fblangref25-dml-merge.html
Or, without adding the column into the table, but making a "virtual" column in the query, joining the table upon itself.
https://en.wikipedia.org/wiki/Join_(SQL)#Left_outer_join
SELECT T1.*, T2.Vehicle as Flag
FROM MyTable T1
LEFT JOIN MyTable T2
ON (T2.ID = T1.ID - 1) AND (T2.pos_buildcount <> 255)
Granted it would only work if ID column would be filled with integers with no gaps. Otherwise there would be other definitions what "prior record" means than T2.ID = T1.ID - 1, but the idea holds. Define what "prior" means in terms of real data on real columns and then you can compare the table with itself.

In Oracle 11g, how to change the order of the results of a sql without "order by"? [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 9 years ago.
Improve this question
Now I have a very simple SQL:
select * from table A
I know the results will be sorted by "rowid"(I'm not very sure, I'm a freshman).
And Oracle will not guarantee the order of the results of a SQL without "order by".
Here's my question:
Once I've got results in such order: ....A...B....
Now I want the results in this order: ....B...A....
Just make B before A is OK.
How to do this?
Notice 1: This is an experiment. Please be patient to think about my question.
Notice 2: Do not change the primary key of any record, and do not use any DDL, and use the same SQL "select * from table A".
Notice 3:
create table A(id NUMBER(20) primary key, name VARCHAR2(30));
insert into A values(1,'one');
insert into A values(2,'two');
select * from A;
What I've tried : update, insert ,delete some records, which do not work.
Edit
Given this requirement:
Do not change the SQL select * from table A.
Change the table A to change the results order
the answer is a clear and definite: this is not possible.
(Keeping my initial answer as a reference)
"I know the results will be sorted by rowid" - no, they are not.
The rows will be returned in any order the database thinks is the most efficient.
There is no, absolutely no, guarantee that rows are returned in any specific order unless you specify an ORDER BY.
The ONLY way to get a specific order is to use an ORDER BY.
If you want 'B' to come before 'A' then simply do a descending order:
select *
from table_A
order by some_col DESC
You can put more logic into the ORDER BY operator by applying expressions or functions. If you e.g. want to list 'B' at the top and everything else after that in alphabetical order, you can do something like this:
select *
from table_a
order by
case
when some_col = 'B' then 0
else 1
end,
some_col
You keep trying to "clarify" your question. As best I can understand it, you're attempting to present a "puzzler" of some sort. But your puzzler is nonsensical. What I think you are missing is an understanding of "WHY" the rows are being returned in the order you inserted them. When you understand that, you'll have a better appreciation of what your question is actually asking, and why you won't be able to solve it.
If you
1) create a standard Oracle table "A" with PK ID and one (or more) other columns and
2) insert just a couple rows (e.g. less data than will fill a datablock),
3) do no subsequent indexing, moves, reorgs, compression, etc
then yes, all existing implementations of Oracle will resolve SELECT * FROM A by returning your two rows in the same order you inserted them.
This is because
1) current Oracle implementations will write new records to an empty datablock in the order they were received and
2) subsequent SELECT * FROM A, if there is no index which offers a better plan, will cause a full-table-scan. Since all of your data will be in a single datablock, and current Oracle implementations read data within a block sequentially, "SELECT * FROM A" will "stably" return rows in the order you inserted them.
In that context, your puzzler seems to be: can a person issue INSERT/UPDATE/DELETE statements against TABLE A such that current Oracle implementations will execute "SELECT * FROM TABLE A" and return your two rows in reverse order. Such a challenge is trivially (and really only) solved by, e.g., deleting your two rows and re-inserting them with the ID=2 row first and ID=1 row second. But your statement "Do not change the primary key of any record" indicates that deleting/re-inserting isn't an option. In which case, yes, you're asking for the impossible, even from a puzzling perspective: your challenge is to wave a magic wand at Oracle such that it will start reading rows within the same datafile from end-to-start.
ETA: You also disallowed DDL; otherwise, you could do an amusing hack like this to get the desired effect:
create table A(id NUMBER(5) primary key, name VARCHAR2(10))
partition by list (id)
(partition p1 values (2),
partition p2 values (1));
insert into A values(1,'one');
insert into A values(2,'two');
select * from a;
ID NAME
---- ---------
2 two
1 one
Only
ORDER BY
is there for the work. But you can do the required arrangement by making a simple function with the logic you want behind the format of the returned rows and use that function.

SELECT COUNT(*) ;

I have a database, database1, with two tables (Table 1, Table2) in it.
There are 3 rows in Table1 and 2 rows in Table2. Now if I execute the following SQL query SELECT COUNT(*); on database1, then the output is "1".
Does anyone has the idea, what this "1" signifies?
The definition of the two tables is as below.
CREATE TABLE Table1
(
ID INT PRIMARY KEY,
NAME NVARCHAR(20)
)
CREATE TABLE Table2
(
ID INT PRIMARY KEY,
NAME NVARCHAR(20)
)
Normally all selects are of the form SELECT [columns, scalar computations on columns, grouped computations on columns, or scalar computations] FROM [table or joins of tables, etc]
Because this allows plain scalar computations we can do something like SELECT 1 + 1 FROM SomeTable and it will return a recordset with the value 2 for every row in the table SomeTable.
Now, if we didn't care about any table, but just wanted to do our scalar computed we might want to do something like SELECT 1 + 1. This isn't allowed by the standard, but it is useful and most databases allow it (Oracle doesn't unless it's changed recently, at least it used to not).
Hence such bare SELECTs are treated as if they had a from clause which specified a table with one row and no column (impossible of course, but it does the trick). Hence SELECT 1 + 1 becomes SELECT 1 + 1 FROM ImaginaryTableWithOneRow which returns a single row with a single column with the value 2.
Mostly we don't think about this, we just get used to the fact that bare SELECTs give results and don't even think about the fact that there must be some one-row thing selected to return one row.
In doing SELECT COUNT(*) you did the equivalent of SELECT COUNT(*) FROM ImaginaryTableWithOneRow which of course returns 1.
Along similar lines the following also returns a result.
SELECT 'test'
WHERE EXISTS (SELECT *)
The explanation for that behavior (from this Connect item) also applies to your question.
In ANSI SQL, a SELECT statement without FROM clause is not permitted -
you need to specify a table source. So the statement "SELECT 'test'
WHERE EXISTS(SELECT *)" should give syntax error. This is the correct
behavior.
With respect to the SQL Server implementation, the FROM
clause is optional and it has always worked this way. So you can do
"SELECT 1" or "SELECT #v" and so on without requiring a table. In
other database systems, there is a dummy table called "DUAL" with one
row that is used to do such SELECT statements like "SELECT 1 FROM
dual;" or "SELECT #v FROM dual;". Now, coming to the EXISTS clause -
the project list doesn't matter in terms of the syntax or result of
the query and SELECT * is valid in a sub-query. Couple this with the
fact that we allow SELECT without FROM, you get the behavior that you
see. We could fix it but there is not much value in doing it and it
might break existing application code.
It's because you have executed select count(*) without specifying a table.
The count function returns the number of rows in the specified dataset. If you don't specify a table to select from, a single select will only ever return a single row - therefore count(*) will return 1. (In some versions of SQL, such as Oracle, you have to specify a table or similar database object; Oracle includes a dummy table (called DUAL) which can be selected from when no specific table is required.)
you wouldn't normally execute a select count(*) without specifying a table to query against. Your database server is probably giving you a count of "1" based on default system table it is querying.
Try using
select count(*) from Table1
Without a table name it makes no sense.
without table name it always return 1 whether it any database....
Since this is tagged SQL server, the MSDN states.
COUNT always returns an int data type value.
Also,
COUNT(*) returns the number of items in a group. This includes NULL
values and duplicates.
Thus, since you didn't provide a table to do a COUNT from, the default (assumption) is that it returns a 1.
COUNT function returns the number of rows as result. If you don't specify any table, it returns 1 by default. ie., COUNT(*), COUNT(1), COUNT(2), ... will return 1 always.
Select *
without a from clause is "Select ALL from the Universe" since you have filtered out nothing.
In your case, you are asking "How many universe?"
This is exactly how I would teach it. I would write on the board on the first day,
Select * and ask what it means. Answer: Give me the world.
And from there I would teach how to filter the universe down to something meaningful.
I must admit, I never thought of Select Count(*), which would make it more interesting but still brings back a true answer. We have only one world.
Without consulting Steven Hawking, SQL will have to contend with only 1.
The results of the query is correct.