Update records by joining local and foreign db using db link - sql-update

t - current db table
table1 - other db
database - current db table where the "other db" credentials are stored
SELECT
t.*
FROM "database" d, t,
dblink_exec(
format('dbname = %s host = %s port = %s user = %s password = %s', databasename, servername, port, username, "password"),
format('UPDATE
table1 a
SET
(col1, col2) = (SELECT
%L :: json, now()
FROM t b -- t is the local table (from current db)
WHERE b.col2 = a.col2
AND b.col3 = a.col3
AND b.col4 = a.col4)
WHERE a.col2 = ''ABC''
AND a.col3 = ''DEF''
', data )) -- column data is from table ```t```
WHERE databasename = 'otherdb';
How to update the records by joining local table to other db. I need the table t to stick in the correct place. I can't run this on other db as there are other dependencies (mostly timing).

I was able to achieve this by JOINING the tables first and form the UPDATE statement and feed the UPDATE statement to the dblink_exec.
SELECT
dblink_exec(
format('dbname = %s host = %s port = %s user = %s password = %s', databasename, servername, port, username, "password"),
format ('UPDATE table1 %1$sSET col4 = %3$L :: json, %2$scol3 = now() %1$sWHERE col3 = %4$L %2$sAND col3 = ''ABC'' %2$sAND col2 = ''DEF'';',
E'\n',
E'\n\t',
t.data,
t.col3
)
)
FROM t
INNER JOIN
(
SELECT x.*
FROM "database" d,
dblink(
format('dbname = %s host = %s port = %s user = %s password = %s',
databasename, servername, port, username, "password"
),
'SELECT
*
FROM table1
WHERE col1 = ''ABC''
AND col2 = ''DEF''
'
) AS x( col1 TEXT,
col2 TEXT,
col3 TEXT,
col4 TEXT
)
WHERE databasename = 'otherdb'
) as otherdb
CROSS JOIN "database" d
ON otherdb.col1 = t.col1
AND otherdb.col2 = t.col2
AND otherdb.col1 = 'DEF'
AND otherdb.col2 = 'ABC'
WHERE databasename = 'otherdb';

Related

Flask SQLAlchemy does not create all the columns of my model

I am using flask and flask SQLAlchemy to create my sqllite database that has one table with several columns. I have created my model but once I run the app it only creates the first 03 columns ?!!!
...
db = SQLAlchemy()
def setup_db(app):
db.app = app
db.init_app(app)
def db_drop_and_create_all():
db.drop_all()
db.create_all()
...
#dataclass
class ChurnModel(inheritedModels):
id = int
customerID = String
gender = String
SeniorCitizen: int
Partner: String
...
__tablename__ = 'churn'
id = Column(Integer().with_variant(Integer, "sqlite"), primary_key=True)
customerID = Column(String(255), nullable=False)
gender = Column(String(255))
SeniorCitizen: Column(Integer())
Partner: Column(String(255))
...
def get_churn(self):
return {
"id": self.id,
"customerID": self.customerID,
"gender": self.gender,
"SeniorCitizen": self.SeniorCitizen,
"Partner": self.Partner,
...
}
...
This is what I have found in the database.db file surrounded by a lot of nulls:
TE TABLE churn (
id INTEGER NOT NULL,
"customerID" VARCHAR(255) NOT NULL,
gender VARCHAR(255),
PRIMARY KEY (id)
)
Any explanation?!
After looking at the code, I think this is an expected behaviour since the only columns you defined are id, customerID, and gender.
Maybe you just got confused on how to use type hints, or you didn't pay attention to that, that's all.
Try this instead :
#dataclass
class ChurnModel(inheritedModels):
id: int
customerID: str
gender: str
SeniorCitizen: int
Partner: str
...
__tablename__ = 'churn'
id = Column(Integer().with_variant(Integer, "sqlite"), primary_key=True)
customerID = Column(String(255), nullable=False)
gender = Column(String(255))
SeniorCitizen= Column(Integer())
Partner= Column(String(255))
...

What happens when I change the default return of __unicode__ method to pass multiples foreignkeys

I'm wondering, in terms of database efficiency, if I edit the return __unicode__ method and do something like this:
class AnyModel(models.Model):
a_field = models.ForeignKey(A)
b_field = models.ForeignKey(B)
def __unicode__(self):
return "A - B: %s - %s " % (self.a_field.a2.a3, self.b_field.b2.b3)
So, the __unicode__ method will hit the foreign key's foreign key's foreign keys, get a string and then return it.
... Is it too expensive? What criteria should I follow? Is there any general advice I could use? Is it better not to write this kind of __unicode__ methods?
This is what happening with this structure:
def __unicode__(self):
return "A - B: %s - %s " % (self.a_field.a2.a3, self.b_field.b2.b3)
Hits :
(0.000) QUERY = 'SELECT "core_a"."id", "core_a"."a2_id" FROM "core_a" WHERE "core_a"."id" = %s' - PARAMS = (2,); args=(2,)
(0.000) QUERY = 'SELECT "core_a2"."id", "core_a2"."a3_id" FROM "core_a2" WHERE "core_a2"."id" = %s' - PARAMS = (1,); args=(1,)
(0.012) QUERY = 'SELECT "core_a3"."id" FROM "core_a3" WHERE "core_a3"."id" = %s' - PARAMS = (1,); args=(1,)
(0.000) QUERY = 'SELECT "core_b"."id", "core_b"."b2_id" FROM "core_b" WHERE "core_b"."id" = %s' - PARAMS = (1,); args=(1,)
(0.000) QUERY = 'SELECT "core_b2"."id", "core_b2"."b3_id" FROM "core_b2" WHERE "core_b2"."id" = %s' - PARAMS = (1,); args=(1,)
(0.005) QUERY = 'SELECT "core_b3"."id" FROM "core_b3" WHERE "core_b3"."id" = %s' - PARAMS = (1,); args=(1,)
But, if you do this,:
def __unicode__(self):
a_relation = AnyModel.objects.select_related('a_field__a2__a3').get(pk=self.pk)
b_relation = AnyModel.objects.select_related('b_field__b2__b3').get(pk=self.pk)
return "A - B: %s - %s " % (a_relation.a_field.a2.a3, b_relation.b_field.b2.b3)
When execute the line :
a_relation = AnyModel.objects.select_related('a_field__a2__a3').get(pk=self.pk)
1 hit :
(0.000) QUERY = 'SELECT "core_anymodel"."id", "core_anymodel"."a_field_id", "core_anymodel"."b_field_id", "core_a"."id", "core_a"."a2_id", "core_a2"."id", "core_a2"."a3_id", "core_a3"."id" FROM "core_anymodel" INNER JOIN "core_a" ON ( "core_anymodel"."a_field_id" = "core_a"."id" ) INNER JOIN "core_a2" ON ( "core_a"."a2_id" = "core_a2"."id" ) INNER JOIN "core_a3" ON ( "core_a2"."a3_id" = "core_a3"."id" ) WHERE "core_anymodel"."id" = %s' - PARAMS = (1,); args=(1,)
and When execute the second line:
b_relation = AnyModel.objects.select_related('b_field__b2__b3').get(pk=self.pk)
+1 Hit:
(0.000) QUERY = 'SELECT "core_anymodel"."id", "core_anymodel"."a_field_id", "core_anymodel"."b_field_id", "core_b"."id", "core_b"."b2_id", "core_b2"."id", "core_b2"."b3_id", "core_b3"."id" FROM "core_anymodel" INNER JOIN "core_b" ON ( "core_anymodel"."b_field_id" = "core_b"."id" ) INNER JOIN "core_b2" ON ( "core_b"."b2_id" = "core_b2"."id" ) INNER JOIN "core_b3" ON ( "core_b2"."b3_id" = "core_b3"."id" ) WHERE "core_anymodel"."id" = %s' - PARAMS = (1,); args=(1,)
And when execute
return "A - B: %s - %s " % (self.a_field.a2.a3, self.b_field.b2.b3)
Doesn't hit the database.
.
1 - Edit
You can join this, to :
def __unicode__(self):
relation = AnyModel.objects.select_related('a_field__a2__a3', 'b_field__b2__b3').get(pk=self.pk)
return "A - B: %s - %s " % (relation.a_field.a2.a3, relation.b_field.b2.b3)
and will hit only once.
(0.000) QUERY = 'SELECT "core_anymodel"."id", "core_anymodel"."a_field_id", "core_anymodel"."b_field_id", "core_a"."id", "core_a"."a2_id", "core_a2"."id", "core_a2"."a3_id", "core_a3"."id", "core_b"."id", "core_b"."b2_id", "core_b2"."id", "core_b2"."b3_id", "core_b3"."id" FROM "core_anymodel" INNER JOIN "core_a" ON ( "core_anymodel"."a_field_id" = "core_a"."id" ) INNER JOIN "core_a2" ON ( "core_a"."a2_id" = "core_a2"."id" ) INNER JOIN "core_a3" ON ( "core_a2"."a3_id" = "core_a3"."id" ) INNER JOIN "core_b" ON ( "core_anymodel"."b_field_id" = "core_b"."id" ) INNER JOIN "core_b2" ON ( "core_b"."b2_id" = "core_b2"."id" ) INNER JOIN "core_b3" ON ( "core_b2"."b3_id" = "core_b3"."id" ) WHERE "core_anymodel"."id" = %s' - PARAMS = (1,); args=(1,)

Many to one relation not working in fields.selection() in openerp

I need to create a selection field in openerp , it's values should load from a function and also this field needs many2one relation with another table.I have created the selection field and values are loaded from the function but many2one relation not working in it.below given is my code.
def _sel_proj(self, cr, uid, context=None):
cr.execute("""SELECT project.id,account.name FROM project_project project
LEFT JOIN account_analytic_account account ON
account.id = project.analytic_account_id
LEFT JOIN project_user_rel rel ON rel.project_id = project.id
WHERE (account.user_id = %s or rel.uid = %s)
GROUP BY project.id,account.name"""%(uid, uid))
return [(r[0],r[1]) for r in cr.fetchall()]
_name = 'mat.mgmt'
_columns = {'project_id':fields.selection(_sel_proj,string='Project',type="many2one",relation="project.project",select="true",required="true"),}
change the field project_id to many2one and in the view for the field add widget='selection'.
in python:
_columns = {'project_id':fields.many2one('project.project','Project',select="true",required="true"),}
in xml:
<field name="project_id" widget="selection"/>
then override the fields_view_get function and add the filter condition for project_id. For example
def fields_view_get(self, cr, uid, view_id=None, view_type=False, context=None, toolbar=False, submenu=False):
if context is None:context = {}
res = super(<your_class_name>,self).fields_view_get(cr, uid, view_id=view_id, view_type=view_type, context=context, toolbar=toolbar, submenu=submenu)
for field in res['fields']:
if field == 'project_id':
cr.execute("""SELECT project.id,account.name FROM project_project project
LEFT JOIN account_analytic_account account ON
account.id = project.analytic_account_id
LEFT JOIN project_user_rel rel ON rel.project_id = project.id
WHERE (account.user_id = %s or rel.uid = %s)
GROUP BY project.id,account.name"""%(uid, uid))
project_select = [(r[0],r[1]) for r in cr.fetchall()]
res['fields'][field]['selection'] = project_select
return res

how to generate this sql in sqlalchemy,i am trying hard but didn't know what to do

"select pck.id, pck.name, deb.last_time from (select id, name from dp_package where name like %s limit %s, %s) as pck left join (select package_id, last_time from dp_deb where id in (select max(id) from dp_deb group by package_id)) as deb on pck.id = deb.package_id" %(keyword, start, limit)
Assuming the model is defined:
Base = declarative_base()
class Package(Base):
__tablename__ = 'db_package'
id = Column(Integer, primary_key=True)
name = Column(String)
def __init__(self, name):
self.name = name
class Deb(Base):
__tablename__ = 'db_deb'
id = Column(Integer, primary_key=True)
package_id = Column(Integer, ForeignKey('db_package.id'))
name = Column(String)
last_time = Column(DateTime)
def __init__(self, name, last_time):
self.name = name
self.last_time = last_time
packages = relationship(Package, backref="debs")
the code below should produce the same result (although different SQL query, where one subquery is replaced with simple LEFT OUTER JOIN):
# query parameters
keyword, start, limit = 'xxx', 1, 3
# subquery for the last_time
sq2h = session.query(Deb.package_id, func.max(Deb.id).label("max_id")).group_by(Deb.id).subquery("max_deb")
sq2 = (session.query(Deb.package_id, Deb.last_time).
join(sq2h, Deb.id == sq2h.c.max_id))
sq2 = sq2.subquery("deb")
qry = (session.query(Package.id, Package.name, sq2.c.last_time).
outerjoin(sq2, sq2.c.package_id == Package.id).
filter(Package.name.contains(keyword))
)[start:(start + limit)]
print qry
producing this SQL for SQLite:
SELECT db_package.id AS db_package_id,
db_package.name AS db_package_name,
deb.last_time AS deb_last_time
FROM db_package
LEFT OUTER JOIN(SELECT db_deb.package_id AS package_id, db_deb.last_time AS last_time
FROM db_deb
JOIN (SELECT db_deb.package_id AS package_id,
max(db_deb.id) AS max_id
FROM db_deb
GROUP BY db_deb.id
) AS max_deb
ON db_deb.id = max_deb.max_id
) AS deb
ON deb.package_id = db_package.id
WHERE db_package.name LIKE '%%' || ? || '%%'
LIMIT ? OFFSET ?
('xxx', 3, 1)

Relation between models with composite keys

I have two models with composite keys:
class ContestUser(models.Model):
user_id = models.IntegerField(primary_key = True)
contest_id = models.IntegerField(primary_key = True)
username = models.CharField(max_length = 1536, blank = True)
.
.
.
class ContestRegistration(models.Model):
user_id = models.IntegerField(primary_key = True)
contest_id = models.IntegerField(primary_key = True)
status = models.IntegerField(choices = EJUDGE_CONTEST_STATUSES)
.
.
.
First question is How can I relate them, and query like in join.
Select * from ContestRegistration r join ContestUser u on r.user_id = u.user_id and r.contest_id = u.contest_id where r.contest_id = 3;
Second is How to save an object like this?
cuser = ContestUser.objects.get(user_id = 1, contest_id = 1)
cuser.username = 'username'
cuser.save()
This results in IntegrityError: (1062, "Duplicate entry '1-1' for key 'PRIMARY'")
Executed SQL is:
SELECT * FROM `users` WHERE (`users`.`contest_id` = 1 AND `users`.`user_id` = 1 );
SELECT (1) AS `a` FROM `users` WHERE `users`.`user_id` = 1 LIMIT 1;
UPDATE `users` SET ... WHERE `users`.`user_id` = 1 ;
Django models don't support multiple primary keys: https://docs.djangoproject.com/en/1.3/faq/models/#do-django-models-support-multiple-column-primary-keys
However, as the documentation describes, you can use other properties on ForeignKey fields, like unique_together to do the same thing. Hope that helps you out.