So far I've got basically the following:
MyTable.query
.join(…)
.filter(…)
The filter has a complicated case insensitive prefix check:
or_(*[MyTable.name.ilike("{}%".format(prefix)) for prefix in prefixes])
Now I have to retrieve the matching prefix in the result. In pseudo-SQL:
SELECT CASE
WHEN strpos(lower(my_table.foo), 'prefix1') = 0 THEN 'prefix1'
WHEN …
END AS prefix
WHERE prefix IS NOT NULL;
The SQLAlchemy documentation demonstrates how to use CASE within WHERE, which seems like a strange edge case, and not how to use it to get a new column based on an existing one.
The goal is to avoid duplicating the logic and prefix names anywhere.
You know that case is an expression. You can use it in any place where SQL allows it, and link to docs you have provided show how to construct the case expression.
from sqlalchemy import case, literal
from sqlalchemy.orm import Query
q = Query(case([
(literal(1) == literal(1), True),
], else_ = False))
print(q)
SELECT CASE WHEN (:param_1 = :param_2) THEN :param_3 ELSE :param_4 END AS anon_1
Related
In PostgreSQL you can use an expression which is able to make use of the column values for the given row to define the value in the set statement i.e
UPDATE some_table
SET col_a = (col_b != 1)
WHERE col_c = 'some val'
Is there a way to do this in JOOQ? - I've looked through the JOOQ documentation, but I can't see any reference to it
I'm assuming col_a is a Field<Boolean>, in case of which, you can wrap a Condition in a Field<Boolean> expression using DSL.field(Condition)
// As always, assuming you have this static import:
import static org.jooq.impl.DSL.*;
ctx.update(SOME_TABLE)
.set(SOME_TABLE.COL_A, field(SOME_TABLE.COL_B.ne(1)))
.where(SOME_TABLE.COL_C.eq("some val"))
.execute();
Following https://www.jooq.org/doc/3.13/manual/sql-building/sql-statements/update-statement/#N6ABB6, I think you would do
update(SOME_TABLE)
.set(row(SOME_TABLE.A),
row(SOME_TABLE.B.neg()))
.where(SOME_TABLE.C.eq("some val"));
I need a window function that partitions by some keys (=column names), orders by another column name and returns the rows with top x ranks.
This works fine for ascending order:
def getTopX(df: DataFrame, top_x: String, top_key: String, top_value:String): DataFrame ={
val top_keys: List[String] = top_key.split(", ").map(_.trim).toList
val w = Window.partitionBy(top_keys(1),top_keys.drop(1):_*)
.orderBy(top_value)
val rankCondition = "rn < "+top_x.toString
val dfTop = df.withColumn("rn",row_number().over(w))
.where(rankCondition).drop("rn")
return dfTop
}
But when I try to change it to orderBy(desc(top_value)) or orderBy(top_value.desc) in line 4, I get a syntax error. What's the correct syntax here?
There are two versions of orderBy, one that works with strings and one that works with Column objects (API). Your code is using the first version, which does not allow for changing the sort order. You need to switch to the column version and then call the desc method, e.g., myCol.desc.
Now, we get into API design territory. The advantage of passing Column parameters is that you have a lot more flexibility, e.g., you can use expressions, etc. If you want to maintain an API that takes in a string as opposed to a Column, you need to convert the string to a column. There are a number of ways to do this and the easiest is to use org.apache.spark.sql.functions.col(myColName).
Putting it all together, we get
.orderBy(org.apache.spark.sql.functions.col(top_value).desc)
Say for example, if we need to order by a column called Date in descending order in the Window function, use the $ symbol before the column name which will enable us to use the asc or desc syntax.
Window.orderBy($"Date".desc)
After specifying the column name in double quotes, give .desc which will sort in descending order.
Column
col = new Column("ts")
col = col.desc()
WindowSpec w = Window.partitionBy("col1", "col2").orderBy(col)
I'm trying to match some names with the names I already have in my Postgresql database, using the following code:
last_like = '{last_name}%'.format(last_name)
matches = Session.query(MyTable).filter(or_(
MyTable.name.ilike(last_like),
MyTable.other_names.any(last_like, operator=ilike_op),
)).all()
Essentially it tries to match the name column or any of the other names stored as an array in the other_names column.
But I get:
KeyError: <function ilike_op at 0x7fb5269e2500>
What am I doing wrong?
For use postgresql array field you need to use unnest() function.
But you can't use result of unnest() in where clause.
Instead, you can use array_to_string function. Searching on string of other_names will give the same effect
from sqlalchemy import func as F
last_like = "%qq%"
matches = session.query(MyTable).filter(or_(
MyTable.name.ilike(last_like),
F.array_to_string(MyTable.other_names, ',').ilike(last_like),
)).all()
Probably something really trivial but I haven't quite found the answer I am looking for on the internet and I get syntax errors with this. What I want/need to do is to provide a special case in my where clause where the doctype is 1. If it is, then it needs to match the claimID from a sub select of a temp table. If the doctype is not a 1 then we just need to continue on and ignore the select.
AND
CASE
WHEN #DocType = 1 THEN (c.ClaimID IN (SELECT TNE.ClaimID FROM TNE)
END
I have seen some for if statements but I didn't seem to get that to work and haven't found anything online as of yet that shows a case statement doing what I would like. Is this even possible?
You don't need a case statement, you could do:
AND (#DocType <> 1 or c.ClaimID in (SELECT TNE.ClaimID FROM TNE))
A CASE expression (not statement) returns a single value. SQL Server supports the bit data type. (Valid values are 0, 1, 'TRUE' and 'FALSE'.) There is a boolean data type (with values TRUE, FALSE and UNKNOWN), but you cannot get a firm grip on one. Your CASE expression attempts to return a boolean, give or take the unmatched parenthesis, which is not supported in this context.
You could use something like this, though Luc's answer is more applicable to the stated problem:
and
case
when #DocType = 1 and c.ClaimId in ( select TNE.ClaimId from TNE ) then 1
when #DocType = 2 and ... then 1
...
else 0
end = 1
Note that the CASE returns a value which you must then compare (= 1).
It seems like Django by default adds ORDER BY to queries. Can I clear it?
from slowstagram.models import InstagramMedia
print InstagramMedia.objects.filter().query
SELECT
`slowstagram_instagrammedia`.`id`,
`slowstagram_instagrammedia`.`user_id`,
`slowstagram_instagrammedia`.`image_url`,
`slowstagram_instagrammedia`.`video_url`,
`slowstagram_instagrammedia`.`created_time`,
`slowstagram_instagrammedia`.`caption`,
`slowstagram_instagrammedia`.`filter`,
`slowstagram_instagrammedia`.`link`,
`slowstagram_instagrammedia`.`attribution_id`,
`slowstagram_instagrammedia`.`likes_count`,
`slowstagram_instagrammedia`.`type`
FROM
`slowstagram_instagrammedia`
ORDER BY
`slowstagram_instagrammedia`.`id`
ASC
```
Actually, just do a query.order_by() is enough.
This is specified in the docs although it is a bit hard to find. The docs say:
If you don’t want any ordering to be applied to a query, not even the default ordering, call order_by() with no parameters.
Here is the implementation of order_by, for your reference -
def order_by(self, *field_names):
"""
Returns a new QuerySet instance with the ordering changed.
"""
assert self.query.can_filter(), \
"Cannot reorder a query once a slice has been taken."
obj = self._clone()
obj.query.clear_ordering(force_empty=False)
obj.query.add_ordering(*field_names)
return obj
You can use: clear_ordering method from query
"""Removes any ordering settings.
If 'force_empty' is True, there will be no ordering in the resulting
query (not even the model's default).
"""
Example:
>>> from products.models import Product
>>> products = Product.objects.filter(shortdesc='falda').order_by('id')
>>> print products.query
SELECT "products_product"."id", "products_product"."shortdesc"
WHERE "products_product"."shortdesc" = falda
ORDER BY "products_product"."id" ASC
>>> products.query.clear_ordering()
>>> print products.query
SELECT "products_product"."id", "products_product"."shortdesc"
WHERE "products_product"."shortdesc" = falda
Try to use .order_by('?') at the end of queryset.