Cassandra CQL where clause parentheses - cassandra

Having this Entity
#Table(keyspace = KEYSPACE)
public class CE_TimeSeries extends Entity implements TimeSeriesPoint{
#PartitionKey(1)
private String typeId;
#ClusteringColumn(value=1, asc=true)
private String userId;
#ClusteringColumn(value=2, asc=true)
private Date startDate;
#Column
private Date endDate;
#Column
private int groupInterval;
#Column
private int interval;
}
This CQL
SELECT startDate, endDate, groupInterval, interval FROM CE_TimeSeries WHERE typeId
= :typeId and userId = :userId and ( endDate >= :fromDate or ( startDate >=
:fromDate and startDate <= :toDate ) )
Give the Exception :
Caused by: com.datastax.driver.core.exceptions.SyntaxError: line 1:142
mismatched input 'or' expecting ')' (... ( endDate >= :fromDate [or] (...)

While I don't actually see a question here, I'll assume that you are wondering why you are getting an exception. There are two things wrong with your query.
CQL does not allow the use of OR in the WHERE clause.
CQL does not allow parens in the WHERE clause. Plus, not having OR available kind of precludes the need for parens.
The bottom line, is that CQL is not SQL, and the logic you can apply in the WHERE clause is largely dependent on the storage model.

Related

CosmosDB Cassandra API - select in query throws exception

SELECT partition_int, clustering_int, value_string
FROM test_ks1.test WHERE partition_int = ? AND clustering_int IN ?
Prepared select query with in clause throws the following exception:
java.lang.ClassCastException: class com.datastax.oss.driver.internal.core.type.PrimitiveType cannot be cast to class com.datastax.oss.driver.api.core.type.ListType
(com.datastax.oss.driver.internal.core.type.PrimitiveType and com.datastax.oss.driver.api.core.type.ListType are in unnamed module of loader 'app')
at com.datastax.oss.driver.internal.core.type.codec.registry.CachingCodecRegistry.inspectType(CachingCodecRegistry.java:343)
at com.datastax.oss.driver.internal.core.type.codec.registry.CachingCodecRegistry.codecFor(CachingCodecRegistry.java:256)
at com.datastax.oss.driver.internal.core.data.ValuesHelper.encodePreparedValues(ValuesHelper.java:112)
at com.datastax.oss.driver.internal.core.cql.DefaultPreparedStatement.bind(DefaultPreparedStatement.java:159)
Using datastax oss driver - version 4.5.1 and cosmosDB.
The query works with cassadra as docker and works in cqlsh with CosmosDB.
Queries used:
CREATE TABLE IF NOT EXISTS test_ks1.test (partition_int int, value_string text, clustering_int int, PRIMARY KEY ((partition_int),clustering_int))
Prepare the statement: INSERT INTO test_ks1.test (partition_int,clustering_int,value_string) values (?,?,?)
Insert values: 1,1,”a” | 1,2,”b”
Prepare the statement: SELECT partition_int, clustering_int, value_string FROM test_ks1.test WHERE partition_int = ? AND clustering_int IN ?
Execute with parameters 1,List.of(1,2)
The expected parameter is an integer and not list of integers
Sample code of the select prepared statement:
final CqlSessionBuilder sessionBuilder = CqlSession.builder()
.withConfigLoader(loadConfig(sessionConfig));
CqlSession session = sessionBuilder.build();
PreparedStatement statement = session.prepare(
"SELECT partition_int, clustering_int,"
+ "value_string FROM test_ks1.test WHERE partition_int = ? "
+ "AND clustering_int IN ?");
com.datastax.oss.driver.api.core.cql.ResultSet rs =
session.execute(statement.bind(1,List.of(1, 2)));
Is there a workaround to use prepared select queries with in clause?
Thanks.
My suggestion would be to use an work around like this:
//IDS you want to use;
List<Integer> list = Arrays.asList(1, 2);
// Multiply the number of question marks
String markers = StringUtils.repeat("?,", list.size()-1);
//Final query
final String query = "SELECT * FROM test_ks1.test where clustering_int in ("+markers+" ?)";
PreparedStatement prepared = session.prepare(query);
BoundStatement bound = prepared.bind(list.toArray()).setIdempotent(true);
List<Row> rows = session.execute(bound).all();
I have tried on my end and it works with me.
Now on your case you also have another parameter before the IN that you need to include in the parameter list but only after build the markers placeholder.

JPQL query to join multiple tables

i am quite new to JPQL, i have 3 entity class Book,Loan,member, relationship
Loan-Book(#OneToOne)unidirection
Loan-Member(#OneToMany)unidirectional
snippet from my loan class
public class loan implements Serializable{
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private int id;
private String dateofissue;
private String dueDate;
#OneToOne
#JoinColumn(name = "bookid")
private book Bookid;
#ManyToOne
#JoinColumn(name="member_ID")
private member memberid;
when i write a very simple query "Select Loan from loan loan"; i get all the columns including columns member and books because of the relation
how can i write a JPQL query to return selected column book.title,book.id,loan.duedate,member.firstname,member.id from book,loan,member
the purpose of the query is to retrive all the borrowed books, by all member
thank you
You already have mappings define so just directly reference them in JPQL.
select l.Bookid.title, l.Bookid.id, loan.duedate, l.memberid.firstname,
l.memberid.id from loan l;
or you can create aliases also for shorter name.
select book.title, book.id, loan.duedate, member.firstname, member.id
from loan l join l.Book book join l.Member member;

ebean order by with oneToMany property with pagination

I'm trying to get paginates orders, sorted on the cration date of the current version (currentVersion = true)
Here is the Order class :
#Entity
public class Offer extends Model {
#Id
public Long id;
....
#OneToMany(mappedBy = "offer", fetch = FetchType.EAGER)
public List<Version> versions;
...
}
Here is the version class
#Entity
public class Version extends Model {
#Id
public Long id;
#ManyToOne
#JoinColumn(name = "OFFER_ID")
public Offer offer;
public Boolean currentVersion = false;
public Date creation;
...
}
Here is the fetch code as I found on eBean documentation :
Query<Offre> query = Ebean.find(Offer.class);
List<Offer> offers = query.fetch("versions")
.where()
.eq("versions.currentVersion", true)
.orderBy("versions.creation desc nulls last")
.setFirstRow(0)
.setMaxRows(10)
.findPagedList().getList();
Here is the expected SQL
SELECT * FROM
(SELECT /*+ FIRST_ROWS(10) */ rownum rn_, a.* FROM
(SELECT t0.id c0,
...
t0.OPTLOCK c32
FROM offer t0
INNER JOIN version t1 on t0.id = t1.OFFER_ID
ORDER BY t1.creation
) a
WHERE rownum <= 10
) ; --bind()
Here is the actual SQL
First one:
SELECT *
FROM
(SELECT
/*+ FIRST_ROWS(10) */
rownum rn_,
a.*
FROM
( SELECT DISTINCT t0.id c0,
...
t0.id
...
FROM offer t0
JOIN versions u1 ON u1.OFFER_ID = t0.id
WHERE u1.current_version = true
AND u1.current_version = true
ORDER BY t0.id
) a
WHERE rownum <= 10
) ;
Second one :
SELECT t0.OFFER_ID c0,
t0.id c1,
...
t0.creation c3,
...
t0.current_version c12,
...
t0.OFFER_ID c30,
...
FROM versions t0
WHERE (t0.OFFER_ID) IN (990,991,992,993,994,995,996,997,998,999)
ORDER BY t0.creation;
Question : What do I need to change to get the expected SQL ?
Thank you very much for help
Versions used :
ebean 7.6.1 from play 2.5.14
I found a walk-around:
Instead of
List<Offer> offers = query.fetch("versions")
.where()
.eq("versions.currentVersion", true)
.orderBy("versions.creation desc nulls last")
.setFirstRow(0)
.setMaxRows(10)
.findPagedList().getList();
I've found :
List<Offer> offers = query.fetch("versions")
.where()
.eq("versions.currentVersion", true)
.orderBy("u1.creation desc") // <-- line with the change
.setFirstRow(0)
.setMaxRows(10)
.findPagedList().getList();
I make sure that the join between offer and versions is made only once and than assume that version join alias will be u1.
At least, it's doning the job.
Bye

Why a localDate field is "nullable = false"

When I generate a table with field LocalDate, it will be mandatory.
#Column(name = "supported_date", nullable = false)
private LocalDate supportedDate;
I don't understand this rule.
It's right there in the #Column annotation: nullable = false means that the column is not nullable, which means that it cannot contain null values, which means that the column is required.

JPQL BETWEEN Date Interval

I tried to get all MainIntervals in a certain date interval. But I get always null.
Here is the JPA Entity
#Table(name="MAIN_INTERVAL")
#NamedQueries({
#NamedQuery(name = MainInterval.FIND_ALL, query = " select m from MainInterval m"),
#NamedQuery(name = MainInterval.FIND_BETWEEN,
query = "select m from MainInterval m where m.mainIntervalStart
BETWEEN :startDate AND :endDate
AND m.mainIntervalEnd BETWEEN :startDate AND :endDate"
) })
public class MainInterval implements Serializable {
public static final String FIND_ALL = "MainInterval.findAll";
public static final String FIND_BETWEEN = "MainInterval.findBetween";
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name="MAIN_INTERVAL_ID")
private Long id;
#Column(name="MAIN_INTERVAL_START")
#Temporal(javax.persistence.TemporalType.DATE)
private Date mainIntervalStart;
#Column(name="MAIN_INTERVAL_END")
#Temporal(javax.persistence.TemporalType.DATE)
private Date mainIntervalEnd; }
And in the EJB SessionBeans I have the method:
public List<MainInterval> findMainIntervalsBetween(Date startDate, Date endDate){
List<MainInterval> resultList = em.createNamedQuery(MainInterval.FIND_BETWEEN, MainInterval.class)
.setParameter("startDate", startDate, TemporalType.DATE).setParameter("endDate", endDate, TemporalType.DATE).getResultList();
return resultList;
}
But when I call it from JSF with CDI the resultList is always null. Although I have some MainIntervals that meet the conditions between startDate and endDate.
I would be very grateful to every answer or links for tutorial.
Best regards!
Your query is:
select m from MainInterval m where m.mainIntervalStart
BETWEEN :startDate AND :endDate
AND m.mainIntervalEnd BETWEEN :startDate AND :endDate
Your first row's interval is [01.05.2012, 31.05.2012], and your second row's interval is [01.05.2012, 01.08.2012]. The arguments of the query are 10.05.2012, 20.05.2012.
So, for your first row:
m.mainIntervalStart BETWEEN :startDate AND :endDate
01.05.2012 BETWEEN 10.05.2012 AND 20.05.2012 : false
So the first row is not returned.
For your second row:
m.mainIntervalStart BETWEEN :startDate AND :endDate
01.05.2012 BETWEEN 10.05.2012 AND 20.05.2012 : false
So the second row isn't returned either.
Everything looks normal to me.

Resources