How can I get update rows with mybatis? - mybatis

If I use mybatis, I can easily get the count of updated rows, just like
update table set desc = 'xxx' where name = ?
However, if I want to get the updated rows, not the count, how can I achieve this by mybatis?

mybatis itself can't do that because this update happens in database and no row data is returned back.
The only option is to modify the query and make it update and select the data you need. The exact way how to achieve this effect depends on the database you are using and/or driver support.
In postgres for example you can change the query and add RETURNING clause like this:
UPDATE table
SET desc = 'xxx'
WHERE name = ?
RETURNING *
This will turn this query to a select one and you can map it as select query in mybatis. Some other databases have similar features.
Another option (if you database and/or JDBC driver support this) is to do two queries, update and select like this
<select id='updateAndReturnModified" resultMap="...">
UPDATE table
SET desc = 'xxx'
WHERE name = #{name};
SELECT *
FROM table
WHERE name = #{name};
</select>
This however may require to use more strict isolation level (READ_COMMITED for example will not work) to make sure the second select sees the state after update and does not see changes made by some concurrent update. Again whether you need this or not depends on the database your are using.

Related

PostgreSQL, allow to filter by not existing fields

I'm using a PostgreSQL with a Go driver. Sometimes I need to query not existing fields, just to check - maybe something exists in a DB. Before querying I can't tell whether that field exists. Example:
where size=10 or length=10
By default I get an error column "length" does not exist, however, the size column could exist and I could get some results.
Is it possible to handle such cases to return what is possible?
EDIT:
Yes, I could get all the existing columns first. But the initial queries can be rather complex and not created by me directly, I can only modify them.
That means the query can be simple like the previous example and can be much more complex like this:
WHERE size=10 OR (length=10 AND n='example') OR (c BETWEEN 1 and 5 AND p='Mars')
If missing columns are length and c - does that mean I have to parse the SQL, split it by OR (or other operators), check every part of the query, then remove any part with missing columns - and in the end to generate a new SQL query?
Any easier way?
I would try to check within information schema first
"select column_name from INFORMATION_SCHEMA.COLUMNS where table_name ='table_name';"
And then based on result do query
Why don't you get a list of columns that are in the table first? Like this
select column_name
from information_schema.columns
where table_name = 'table_name' and (column_name = 'size' or column_name = 'length');
The result will be the columns that exist.
There is no way to do what you want, except for constructing an SQL string from the list of available columns, which can be got by querying information_schema.columns.
SQL statements are parsed before they are executed, and there is no conditional compilation or no short-circuiting, so you get an error if a non-existing column is referenced.

Postgresql update 2 tables in one update statement

I have two different tabs with same field, like:
host.enabled, service.enabled.
How I can update his from 1 update statement?
I tried:
UPDATE hosts AS h, services AS s SET h.enabled=0, s.enabled=0
WHERE
ctid IN (
SELECT hst.ctid FROM hosts hst LEFT JOIN services srv ON hst.host_id = srv.host_id
WHERE hst.instance_id=1
);
On mysql syntax this query worked like this:
UPDATE hosts LEFT JOIN services ON hosts.host_id=services.host_id SET hosts.enabled=0, services.enabled=0 WHERE hosts.instance_id=1
I didn't really understand your schema. If you can set up a fiddle that would be great.
In general though to update two tables in a single query the options are:
Trigger
This makes the assumption that you always want to update both together.
Stored procedure/function
So you'll be doing it as multiple queries in the function, but it can be triggered by a single SQL statement from the client.
Postgres CTE extension
Postgres permits common table expressions (with clauses) to utilise data manipulation.
with changed_hosts as (
update hosts set enabled = true
where host_id = 2
returning *
)
update services set enabled = true
where host_id in (select host_id from changed_hosts);
In this case the update in the WITH statement runs and sets the flag on the hosts table, then the main update runs, which updates the records in the services table.
SQL Fiddle for this at http://sqlfiddle.com/#!15/fa4d3/1
In general though, its probably easiest and most readable just to do 2 updates wrapped in a transaction.

Using a tsql trigger to keep data synced up in two tables

I have a Products table which contains an attribute that will get updated via an ERP update by an end user. When that happens I need the update to be replicated in another table. I am not at all experienced with creating T-SQL triggers but I believe it will accomplish my objective.
Example:
In the IC_Products table:
Productkey = 456
StockLocation = ‘GA-07-A250’
In the IC_ProductCustomFields table (will start out the same because I will run a script to make it so):
Productkey = 456
CustomFieldKey = 13
Value = ‘GA-07-A250’
When the IC_Products.StockLocation column gets updated then I want the value in new IC_ProductCustomFields.Value to also get updated automatically and immediately.
If a new record is created in IC_Products then I want a new record to also be created in IC_ProductCustomFields.
I would like to know how to write the trigger script as well as how to implement it. I am using SQL Server 2005.
You want something like this:
CREATE TRIGGER [dbo].[tr_Products_SyncCustomFields] ON [dbo].[IC_Products]
FOR INSERT, UPDATE
AS
-- First, we'll handle the update. If the record doesn't exist, we'll handle that second
UPDATE IC_ProductCustomFields
SET Value = inserted.StockLocation
FROM IC_ProductCustomFields cf
INNER JOIN inserted -- Yes, we want inserted. In triggers you just get inserted and deleted
ON cf.Productkey = inserted.Productkey AND CustomFieldKey = 13;
-- Now handle the insert where required. Note the NOT EXISTS criteria
INSERT INTO IC_ProductCustomFields (Productkey, CustomFieldKey, Value)
SELECT Productkey, CustomFieldKey, Value
FROM inserted
WHERE NOT EXISTS
(
SELECT *
FROM IC_ProductCustomFields
WHERE Productkey = inserted.Productkey AND CustomFieldKey = 13
);
GO
You could, I think, do separate triggers for insert and update, but this will also have the side-effect of restoring your (supposed?) invariants if the custom fields ever get out of sync; even in an update, if the custom field doesn't exist, this will insert the new record as required to bring it back into compliance with your spec.

Getting Affected Rows by UPDATE statement in RAW plpgsql

This has been asked multiple times here and here, but none of the answers are suitable in my case because I do not want to execute my update statement in a PL/PgSQL function and use GET DIAGNOSTICS integer_var = ROW_COUNT.
I have to do this in raw SQL.
For instance, in MS SQL SERVER we have ##ROWCOUNT which could be used like the following :
UPDATE <target_table>
SET Proprerty0 = Value0
WHERE <predicate>;
SELECT <computed_value_columns>
FROM <target>
WHERE ##ROWCOUNT > 0;
In one roundtrip to the database I know if the update was successfull and get the calculated values back.
What could be used instead of '##ROWCOUNT' ?
Can someone confirm that this is in fact impossible at this time ?
Thanks in advance.
EDIT 1 : I confirm that I need to use raw SQL (I wrote "raw plpgsql" in the original description).
In an attempt to make my question clearer please consider that the update statement affects only one row and think about optimistic concurrency:
The client did a SELECT Statement at first.
He builds the UPDATE and knows which database computed columns are to be included in the SELECT clause. Among other things, the predicate includes a timestamp that is computed each time the rows is updated.
So, if we have 1 row returned then everything is OK. If no row is returned then we know that there was a previous update and the client may need to refresh the data before trying to update clause again. This is why we need to know how many rows where affected by the update statement before returning computed columns. No row should be returned if the update fails.
What you want is not currently possible in the form that you describe, but I think you can do what you want with UPDATE ... RETURNING. See UPDATE ... RETURNING in the manual.
UPDATE <target_table>
SET Proprerty0 = Value0
WHERE <predicate>
RETURNING Property0;
It's hard to be sure, since the example you've provided is so abstract as to be somewhat meaningless.
You can also use a wCTE, which allows more complex cases:
WITH updated_rows AS (
UPDATE <target_table>
SET Proprerty0 = Value0
WHERE <predicate>
RETURNING row_id, Property0
)
SELECT row_id, some_computed_value_from_property
FROM updated_rows;
See common table expressions (WITH queries) and depesz's article on wCTEs.
UPDATE based on some added detail in the question, here's a demo using UPDATE ... RETURNING:
CREATE TABLE upret_demo(
id serial primary key,
somecol text not null,
last_updated timestamptz
);
INSERT INTO upret_demo (somecol, last_updated) VALUES ('blah',current_timestamp);
UPDATE upret_demo
SET
somecol = 'newvalue',
last_updated = current_timestamp
WHERE last_updated = '2012-12-03 19:36:15.045159+08' -- Change to your timestamp
RETURNING
somecol || '_computed' AS a,
'totally_new_computed_column' AS b;
Output when run the 1st time:
a | b
-------------------+-----------------------------
newvalue_computed | totally_new_computed_column
(1 row)
When run again, it'll have no effect and return no rows.
If you have more complex calculations to do in the result set, you can use a wCTE so you can JOIN on the results of the update and do other complex things.
WITH upd_row AS (
UPDATE upret_demo SET
somecol = 'newvalue',
last_updated = current_timestamp
WHERE last_updated = '2012-12-03 19:36:15.045159+08'
RETURNING id, somecol, last_updated
)
SELECT
'row_'||id||'_'||somecol||', updated '||last_updated AS calc1,
repeat('x',4) AS calc2
FROM upd_row;
In other words: Use UPDATE ... RETURNING, either directly to produce the calculated rows, or in a writeable CTE for more complex cases.
Generally the answer to this question depends on the type of the driver used.
PQcmdTuples() function does what is needed, if the application uses libpq. Other libraries on top of libpq need to have some wrapper on top of this function.
For JDBC the Statement.executeUpdate() method seems to the job.
ODBC provides SQLRowCount() function for the similar purpose.

How to use UPDATE ... FROM in SQLAlchemy?

I would like to write this kind of statement in SQLAlchemy / Postgres:
UPDATE slots
FROM (SELECT id FROM slots WHERE user IS NULL
ORDER BY id LIMIT 1000) AS available
SET user='joe'
WHERE id = available.id
RETURNING *;
Namely, I would like to update a limited number of rows matching specified criteria.
PG
I was able to do it this way:
limited_slots = select([slots.c.id]).\
where(slots.c.user==None).\
order_by(slots.c.id).\
limit(1000)
stmt = slots.update().returning(slots).\
values(user='joe').\
where(slots.c.id.in_(limited_slots))
I don't think its as efficient as the original SQL query, however if the database memory is large enough to hold all related segments it shouldn't make much difference.
It's been a while since I used sqlalchemy so consider the following as pseudocode:
for i in session.query(Slots).filter(Slots.user == None):
i.user = "Joe"
session.add(i)
session.commit()
I recommend the sqlalchemy ORM tutorial.