web2py - programmatically insert on one-to-many db - sql

Goodmorning,
I've a DB with three tables :
db.define_table('person',
Field('name', length=100),
Field('dob', length=10),
Field('address', 'text', length=255),
Field('countryname', length=3),
Field('statename', length=100),
)
db.define_table('opslist',
Field('opid', length=10),
Field('dop', length=10),
Field('type_operation', length=25),
)
db.define_table('cardlist',
Field('opid', db.opslist),
Field('name', db.person),
Field('countryname', length=3, required=True),
Field('statename', length=100, required=True),
Field('zip', length=5, required=False),
)
I would insert by code, means not using a sqlform or a form, some data into ...
e.g.: If i have all the values insertable into cardlist table the operation must give me the ability to fill automatically the related record (creating new if not present) into the other tables.
This because it's a relational db with foreign keys ...
Is this possible with web2py using the DAL ? or do i have to write my raw sql command ?
Thank You All

Just use the insert method. It returns the ID of the newly created record, which you can use to insert into the reference fields:
person = db.person.insert(name=..., dob=..., ...)
opslist = db.opslist.insert(opid=..., dop=..., ...)
db.cardlist.insert(opid=opslist, name=person, ...)

Related

Get generated key from column organized table in DB2 Warehouse

I am not able to get generated key from column organized table from an INSERT SQL statement run against IBM DB2 warehouse. I am using Java and JDBC driver. Everything works fine - I am able to connect to DB, create tables, insert data, I am just not able to get a generated key if it is generated in column organized table. Note that row organized tables work fine and return the key properly.
Consider a table:
CREATE TABLE users (
id INTEGER not null GENERATED ALWAYS AS IDENTITY (START WITH 1 INCREMENT BY 1),
username VARCHAR(16),
PRIMARY KEY (id)
);
If this is row organized table I am able to get the generated key fine by using:
PreparedStatement pr = connection.prepareStatement("INSERT INTO users(username) VALUES(?)", PreparedStatement.RETURN_GENERATED_KEYS);
However, If this is column organized table the PreparedStatemnt creation fails with an error:
com.ibm.db2.jcc.am.SqlSyntaxErrorException: DB2 SQL Error: SQLCODE=-1667, SQLSTATE=42858, SQLERRMC=BLUADMIN.USERS;ORGANIZE BY COLUMN;FINAL|NEW|OLD TABLE, DRIVER=4.25.13
Even if I specify columns I want to get returned like so:
PreparedStatement pr = connection.prepareStatement("INSERT INTO users(username) VALUES(?)", new String[]{"id","username"});
pr.setString(1, "test");
pr.executeUpdate();
I get
com.ibm.db2.jcc.am.SqlSyntaxErrorException: DB2 SQL Error: SQLCODE=-1667, SQLSTATE=42858, SQLERRMC=BLUADMIN.USERS;ORGANIZE BY COLUMN;FINAL|NEW|OLD TABLE, DRIVER=4.25.13
on line pr.executeUpdate();.
Does this mean that it is not possible to get generated key from column organized table from the INSERT statement in DB2 Warehouse?
Currently shipping versions v11.1.x and V11.5.x will throw SQL1667N when the query sent to Db2 uses 'FINAL TABLE' or 'OLD TABLE', or 'NEW TABLE' clauses for a column organized table.
When you use the jdbc syntax PreparedStatement.RETURN_GENERATED_KEYS, this syntax may be used under the covers.
Currently those clauses are not supported (i.e. will cause the exception to be thrown) for ORGANIZE BY COLUMN tables. There are other restrictions on column organized tables that you should be aware of before using them.
You can workaround this by creating your tables explicitly with the ORGANIZE BY ROW clause.
Have you tried actually selecting the generated ID? Try something like this:
SELECT ID FROM FINAL TABLE
(INSERT INTO users(username) VALUES(?))
See "Retrieval of result sets from an SQL data change statement" in the IBM Db2 documentation.

Insert into a BigQuery table with a template suffix using the web-ui

Using the Big Query Streaming API its possible to partition tables with a template suffix:
<targeted_table_name> + <templateSuffix>
eg. targettable_suffix
How can this be done from the web ui in an insert statement?
For example:
insert into `project123.dataset123.targettable_suffix`
(`id`, `value`) values ('123', 'abc')
(Where a table exists called targettable but the suffix table has not been created.)
The INSERT statement requires that the target table has been created in advance. Use a CREATE TABLE statement first to create it, then use INSERT. Note that the BigQuery team strongly recommends using partitioned tables instead of multiple tables that share a prefix, however, and if you use a partitioned table, you only need to create it once.

How do you copy Sql table from one database to another database with differ field names

I have a database name "EmpOld" with a table name "Employee" and a database name "EmpNew" with a table name "Employee".
The table structures are identical on both database tables except for the names in the table.
Here is a definition of the tables:
Database "EmpOld" table name "Employee" has following field names:
int e_id
char(20) e_fname
char(25) e_lname
Database "EmpNew" table "Employee" has following field names:
int id
char(20) fname
char(25) lname
Notice, the only difference in the tables is the "e_" prefix for field names are removed from the EmpNew Employee table.
How do I move data from EmpOld database to EmpNew database?
Is there a code that maps these field respectively.
Thanks community,
Nick
Well, you could just name them manually:
INSERT dbo.EmpNew(fname, lname) SELECT e_fname, e_lname FROM dbo.EmpOld;
If you want to do this without manually typing out the column names, there is magic in SSMS - just drag the Columns folder from each table into the appropriate spot in your query window (and then manually remove identity columns, timestamp, computed columns etc. if relevant).
There is no automatic way of mapping fields, unless with some code.
This can be done in two ways:
Using the SQL Import & Export Wizard
This is the most easy way to do this and here is an article that gives step by step to do this. The key is to change the mapping between the source and destination fields while importing the data.
Writing an SQL
This method requires both the databases to be accessible. Using a simple insert statement as follows this can be achieved
insert into EmpNew.dbo.Employee(id, fname, lname)
select
e_id, e_fname, e_lname
from
EmpOld.dbo.Employee
If they are on same sql server then the above will work good as is. If they are different sql server you may have to add a link server connection and prefix the table commands with that.
Is there a code that maps these field respectively.
No - you'll need to provide the mapping. If you're using an ETL tool like SSIS there may be a way to programatically map columns based on some criteria, but nothing built into SQL.
Maybe you can generate code with help from the tables sys.columns and other system tables so that you can make the copy-process run automatically.
I think you can't use:
insert into (...) (...)
because you have two databases. So just generate insert statements like:
insert into table (...) VALUES (...)
Please correct me if i misunderstood the question.
There are 2 ways you can do without the data loss.
1) you can use Insert statement
`
Insert into EmpNew (ID,fname,lname)
Select e_id, e_fname, e_lastname
from EmpOld
`
2) You can simple use Import-Export Wizard
Go to Start Menu > SQL Server 2008/2008R2/2012 > ImportandExport>
This will take you the wizard box
Select Source :- DataSource(ServerName) and Database where you are
extracting data from
Select Destination : DataSource(ServerName) and Database where you are extracting data to
Map the table
BE AWARE of PK/FK/Identity
you are good to go

Should I create a new DB column or not?

I don't know if it is better for me to create a new column in my Mysql database or not.
I have a table :
calculated_data
(id, date, the_value, status)
status is a boolean.
I need an extra value named : the_filtered_value
I can get it easily like this :
SELECT IF(status IS FALSE, 0, the_value) AS the_filtered_value FROM calculated_data
The calculated_data table has millions of entries and I display the_value and the_filtered_value in charts and data tables (using php).
Is it better to create a new column the_filtered_value in the calculated_data table or just use the SELECT IF query?
In "better" I see :
better in performance
better in DB design
easier to maintain
...
Thanks for your help!
Do not add a column. Instead, create a VIEW based on the original data table and in the view add a "virtual" calculated column called the the_filtered_value based on your expression.
In this way you will have easy access to the filtered value without having to copy the "logic" of that expression to different places in your code, while at the same time not storing any derived data. In addition, you will be able to operate directly on the view as if it were a table in most circumstances.
CREATE VIEW calculated_data_ex (id, date, the_value, status, the_filtered_value)
AS SELECT id, date, the_value, status, IF(status IS FALSE, 0, the_value)
FROM calculated_data
Adding the extra field adds complexity to your app but make queries easier (specially when joined on other tables).
I personally always try to keep the data as separated as possible on the database and I handle this cases on my application. Using a MVC pattern makes this task easier.
This works in MS SQL but I do not know if MySQL will support the syntax.
declare #deleteme table (value int, flag bit)
insert #deleteme
Values
(1,'False')
,(2,'true')
Select *, (flag*value) AS the_filtered_value from #deleteme

"Parent Key Not Found" although it exists (within the TX)

I just observed a strange behaviour (of course Oracle is probably supposed to behave this way, but it didn't fit in my world view yet):
I try to insert two rows into a parent and a child table, both within the same transaction:
INSERT INTO V_Parent (ID, Name) VALUES (777, 'Hello World');
INSERT INTO T_Child (ParentID, Name) VALUES (777, 'Foo Bar');
The Child table has a (ParentID) references Parent.ID foreign key constraint.
On the second statement Oracle fails with the error message "Parent key not found."
If I disable the FK constraint, it works. I have asserted that the ParentID and the Parent.ID match, and I am 100% sure that the first line is executed successfully before the second one. Further, I have tried to commit each statement, which worked fine.
However, as the prefixes in my code example suggest, the first INSERT is actually done on a view of the parent table. The reason is that I use NHibernate and the mapping uses the view in background (which didn't cause any problems until today).
Q1: Could it be that inserting on a view is deferred by Oracle so that the second statement fails?
Q2: How can I remedy this problem best?
Do I need to define INSTEAD OF triggers on the views?
Can I change a setting on the VIEW definition?
Can I change a setting on the FOREIGN KEY definition?
(I must not bend the hibernate mapping to the original table: It's a demand to use the views so changes and/or security issues can be hidden behind the views)
Details: C# WinForms Application - NHibernate - Oracle 10.2 - T_Child: Sooner or later I will use a view for that table, too, it's simply not defined yet.
Edit: More Details according to the comments:
The ID is assigned by NHibernate using an Oracle sequence (<generator class="sequence">), and is part of the INSERT statement as in my example. I also verified that the resulting ID in the table row matches the one NHibernate saved in the mapped object.
The view is defined as a SELECT that JOINS some fields of other tables. However, on insert/update I only change the fields belonging to the main table ("T_PARENT"), and that normally works fine.
The current foreign key constraint is not deferrable, but that shouldn't have any effect because the parent statement is executed before the child statement. *)
*) Hmm... let me think: Since I use an NHibernate session for submitting the SQL queries, could it be that NHibernate executes them in a different order than I told it to?
I'll investigate on that. => It seems so, see my own answer.
This is how the actual code looks like:
ISession session = this.DAOFactory.NHibernateHelper.SessionFactory.OpenSession();
ITransaction tx = session.BeginTransaction();
try
{
// parent.ID == 0
session.SaveOrUpdate(parent);
// parent.ID == 777 (for example)
ISQLQuery query = session.CreateSQLQuery(
"INSERT INTO T_CHILD (PARENT_ID, NAME) VALUES (:parentId, :name)");
query.SetDecimal("parentId", parent.ID);
query.SetDecimal("name", "Foo Bar");
query.ExecuteUpdate(); // Fails with ORA-Exception
tx.Commit();
}
catch (Exception)
{
tx.Rollback();
throw;
}
finally
{
session.Close();
}
You don't need to define an INSTEAD OF trigger if the view is already updateable. Inserting in a view that has a simple relation with its base table will behave as inserting in the base table -- consider:
SQL> CREATE TABLE t (a NUMBER, b NUMBER, c NUMBER);
Table created
SQL> CREATE VIEW v AS SELECT a, b FROM t;
View created
SQL> INSERT INTO v VALUES (1,2);
1 row inserted
SQL> SELECT * FROM t;
A B C
---------- ---------- ----------
1 2
For your insert problem, you probably have a BEFORE INSERT trigger on the base table (with the id colomn filled by a sequence).
I've got it.
As stated in the update to my question, it seems that the NHibernate session mixes the order of the SQL statements. To remedy this, I added the following line of code:
session.SaveOrUpdate(parent);
session.Flush();
// (...)
query.ExecuteUpdate();