How can I generate this query using SQLAlchemy's ORM layer?
insert into foo (a,b)
select ‘new’ as a, b
from foo
where a = ‘old’;
Assume I have foo already mapped to a class.
I have seen Insert.from_select, but I'm not sure how I can modify one of the fields like I'm doing in the text query.
A combination of select(), where() and insert().from_select() can do the job:
>>> from sqlalchemy.sql import table, column, select
>>> foo = table('foo', column('a'), column('b'))
>>> print(foo.insert().from_select(['a', 'b'],
select(['"new" as a', 'b']).select_from(foo).where('a = "old"')))
INSERT INTO foo (a, b) SELECT "new" as a, b
FROM foo
WHERE a = "old"
Hope that helps.
Related
I am trying to use the table function file in clickhouse and below are what I have tried.
The background:
test sql:
create table test(a String,b Int32) ENGINE = Memory;--File(CSV)
insert into test (a,b) values ('world',22) ('quant',33);
insert into test (a,b) values ('hello',1);
select * from test;
SELECT a,b FROM test FORMAT Template SETTINGS format_template_resultset = '/home/resultset.format', format_template_row = '/home/row.format', format_template_rows_between_delimiter = '\n';
print:
head
the first:"world",the second:22;
the first:"quant",the second:33;
the first:"hello",the second:1;
end
the fail sql:
SELECT * FROM file("data",Template SETTINGS format_template_resultset = '/home/resultset.format', format_template_row = '/home/row.format', format_template_rows_between_delimiter = '\n', 'a String, b Int32');
print:
Syntax error: failed at position 36 ('SETTINGS'):
SELECT * FROM file("data",Template SETTINGS format_template_resultset = '/home/resultset.format', format_template_row = '/home/row.format', format_template_rows_between_delimiter = '\n', 'a String, b Int32');
Expected one of: DoubleColon, LIKE, GLOBAL NOT IN, end of query, AS, DIV, IS, UUID, OR, QuestionMark, BETWEEN, NOT LIKE, MOD, AND, Comma, alias, IN, ILIKE, Dot, NOT ILIKE, NOT, Arrow, token, NOT IN, GLOBAL IN
I have checked the documentation but it does not seems to be correct. How can I achieve this?
#vladimir s answer is correct,
SELECT * FROM file("data",Template, 'a String, b Int32') SETTINGS format_template_resultset = '/home/resultset.format', format_template_row = '/home/row.format', format_template_rows_between_delimiter = '\n';
thank you.
UPDATE tbl
SET colB = CASE colA
WHEN a THEN x
WHEN b THEN y
END
WHERE colB IN(a, b);
Is there a way to build above query with eloquent / fluent?
Split it in two update queries to keep your code simple:
DB::table('tbl')
->where('colA', 'a')
->whereIn('colB', ['a', 'b'])
->update(['colB' => 'x']);
DB::table('tbl')
->where('colA', 'b')
->whereIn('colB', ['a', 'b'])
->update(['colB' => 'y']);
This question is related to the following question:
How do I INSERT INTO t1 (SELECT * FROM t2) in SQLAlchemy?
but I'd like to specify which columns the insert should work on. That is, I'd like sqlalchemy to generate a query equivalent to
INSERT INTO t1 (col1, col2, col3) SELECT x,y,z FROM t2
I looked at the compilation documentation, but it's not clear to me how to modify the example to be able to specify the column names.
Following modifications might help:
from sqlalchemy.ext.compiler import compiles
from sqlalchemy.sql.expression import Executable, ClauseElement
class InsertFromSelect(Executable, ClauseElement):
def __init__(self, table, columns, select):
self.table = table
self.columns = columns
self.select = select
#compiles(InsertFromSelect)
def visit_insert_from_select(element, compiler, **kw):
return "INSERT INTO %s (%s) %s" % (
compiler.process(element.table, asfrom=True),
", ".join(element.columns), # #note: not a very safe/robust way to compose SQL
compiler.process(element.select)
)
insert = InsertFromSelect(
t1,
("col1", "col2", "col3",),
select([t2.c.x, t2.c.y, t2.c.z])
)
print insert
#necessary import goes here
engine = sqlalchemy.create_engine('mysql://root#127.0.0.1/test',echo=False)
print 'Engine created'
connection=engine.connect()
metadata=MetaData(engine)
metadata.bind=engine
Session = sessionmaker(bind=engine)
session = Session()
mapping = Table('mapping',metadata,autoload=True)
class Mapping(object):
pass
MappingMapper=mapper(Mapping,mapping)
Now i am able to write basic query for insert,update,delete,filter etc.
Q:1 I need to write complex query, where i do derive new columns based on existing columns. Ex. ColA,ColB is there on table, ColC is not part of table structure.
Select (ColA+ColB) as ColC from table where ColC > 50 order by ColC.
I am clueless how to convert above like query with SqlAlchemy. How to map, how to retrieve.
The easiest is to useHybrid Attributes.
In your case, just change the declaration of the class to the following:
from sqlalchemy.ext.hybrid import hybrid_property
class Mapping(object):
#hybrid_property
def ColC(self):
return self.ColA + self.ColB
Then the query:
qry = session.query(Mapping).filter(Mapping.ColC > 80)
will generate SQL:
SELECT mapping.id AS mapping_id, ...
FROM mapping
WHERE mapping."ColA" + mapping."ColB" > ?
In what order would this be evaluated. My intension is that if it finds either foo or bar, it would also search for lol and rofl.
Is this totally in the woods? And if so, how would one evaluate an expression like that.
The AND operator has higher precedence than OR in MySql, so your current expression evaluates as:
WHERE 'foo' OR ('bar' AND 'lol') OR 'rofl'
Add parentheses to the expression if you want to force the evaluation order:
WHERE ('foo' OR 'bar') AND ('lol' OR 'rofl')
AND will be processed first, after that OR will be processed. So, it will be:
'foo' OR ('bar' AND 'lol') OR 'rofl'
After that, it is left to right order.
take a look at the documentation - AND has a higher precedence, so it would be like this:
WHERE 'foo' OR ( 'bar' AND 'lol' ) OR 'rofl'
SELECT
Id, Name
FROM
TestTable
WHERE
(Name = 'foo') OR (Name = 'bar') AND (Name = 'lol') OR (Name = 'rofl')
Will give you the following result in MS SQL Server:
1 foo
4 rofl
So it seems it will combine bar AND lol and evals foo and rofl seperately like this:
SELECT
Id, Name
FROM
TestTable
WHERE
(Name = 'foo') OR ((Name = 'bar') AND (Name = 'lol')) OR (Name = 'rofl')
What you probably want to do is (technically):
SELECT
Id, Name
FROM
TestTable
WHERE
((Name = 'foo') OR (Name = 'bar')) AND ((Name = 'lol') OR (Name = 'rofl'))