I have a table X which has a column BALANCE. I have two row ids and a value amount. There are two constraint variables - MAX_BALANCE and MIN_BALANCE.
I need to write an update query which updates the column BALANCE. The first row id's BALANCE is added with amount and the amount is subtracted from the second row id's BALANCE. I need to ensure that the BALANCE always stays within the range. That is, MIN_BALANCE <= BALANCE <= MAX_BALANCE.
I am not supposed to update one row and then roll back if the number of rows updated is not equal to 2. The update query should either update two rows (success case) or it should not update any row at all.
I am using Hibernate in Java and here is the query which I have tried. It doesn't work for the success case.
String sql = "UPDATE X x "
+ "SET x.balance = CASE "
+ "WHEN x.id = :rowId1 THEN (x.balance + :amount) "
+ "WHEN x.id = :rowId2 THEN (x.balance - :amount) "
+ "END "
+ "WHERE x.id IN :ids "
+ "AND ((x.id = :rowId1 AND x.balance + :amount <= :MAX_BALANCE) "
+ "OR (x.id = :rowId2 AND x.balance - :amount >= :MIN_BALANCE))";
Query query = entityManager.createQuery(sql);
List<BigInteger> ids = Arrays.asList(new BigInteger(rowId1), new BigInteger(rowId2));
int rows = query.setParameter("amount", amount)
.setParameter("ids", ids)
.setParameter("rowId1", new BigInteger(rowId1))
.setParameter("rowId2", new BigInteger(rowId2))
.setParameter("MAX_BALANCE", new Float(MAX_BALANCE))
.setParameter("MIN_BALANCE", new Float(MIN_BALANCE))
.executeUpdate();
I don't want to check if rows == 1 and throw an exception. The update query should always ensure that rows will take the value either 0 or 2.
Or is there a way to perform this operation based on Criteria Update in Hibernate?
You need to self join your table on itself. The first instance should have the record for rowid1 and the 2nd instance should have the record for rowid2. This way you can check the balances of both records in one go and make the decision whether to update or not.
update x x1 join x x2
set x1.balance=if(x1.balance+:amount <= :MAX_BALANCE,x1.balance+:amount, x1.balance),
x2.balance=if(x2.balance-:amount >= :MIN_BALANCE,x2.balance-:amount, x2.balance)
where x1.id=:rowid1 and x2.id=rowid2
try this ...
String sql = "UPDATE X x "
+ "SET x.balance = CASE "
+ "WHEN x.id = :rowId1 AND x.balance + :amount <= :MAX_BALANCE THEN (x.balance + :amount) "
+ "WHEN x.id = :rowId2 AND x.balance - :amount >= :MIN_BALANCE THEN (x.balance - :amount) "
+ "END "
+ "WHERE x.id = :rowId1 OR x.id = :rowId2";
Related
I have pagination in the queue, I also want there to be a limit of 100 items per issue.
That is, with page=14(starting from 0) and size=7, (sum 105) and limit 100, I should get 2 elements.
I'm trying to add a LIMIT but I don't understand how to specify it correctly with pagination
How to add LIMIT 100 to this Query?
(postgresql)
#Query("SELECT * FROM notification WHERE " +
"(user_identifier is null or user_identifier = :userIdentifier) " +
"and (date >= :date) " +
"and (country is null or country = :country) " +
"ORDER BY date desc " +
"OFFSET :page " +
"FETCH NEXT :size ROWS ONLY")
Flux<Element> findAllByUserIdentifierAndCountry(String userIdentifier, Timestamp date, String country, int page, int size);
So far I have used Flux .take() to pick up the required number of items
I am working on Spark SQL and I am trying to get the records using following queries:
/*Select all open tasks which are not unscheduled*/
Dataset<Row> scheduledOpenTasks = sqlContext.sql(
"SELECT * "
+ "FROM OpenTaskTable "
+ "WHERE due_date < cast('" + unscheduledDate + "' as timestamp)");
scheduledOpenTasks.createOrReplaceTempView("ScheduledOpenTaskTable");
/*Select scheduled tasks with max due_date for each csg_order_id*/
Dataset<Row> scheduledTasks = sqlContext.sql(
"SELECT TS1.* from ScheduledOpenTaskTable AS TS1 "
+ "INNER JOIN "
+ " (SELECT csg_order_id, MAX(due_date) AS MaxDD"
+ " FROM ScheduledOpenTaskTable"
+ " GROUP BY csg_order_id) AS TS2 "
+ "ON TS1.csg_order_id = TS2.csg_order_id AND TS1.due_date = TS2.MaxDD");
The unscheduled _date has value 4444-12-30.
In the OpenTaskTable, each csg_order_id can have multiple due_dates including unscheduled_date. I need the csg_order_ids with corresponding highest due_dates except unscheduled_date.
Now, with first query, I am removing all the records which have due_date as unscheduled_date. In second query, I am retrieving all the records with max due_date for each csg_order_id.
Now comes the problem: is there any way to combine these queries as one?
Well, after struggling for a while, finally found a way to combine the above two queries like this:
sqlContext.sql("SELECT OT1.* from OpenTaskTable AS OT1 INNER JOIN "
+ "(SELECT OT2.csg_order_id, MAX(OT2.due_date) AS MaxDD FROM "
+ "(SELECT csg_order_id, due_date from OpenTaskTable WHERE due_date < cast('"+unscheduledDate+"' as timestamp)) AS OT2 "
+ "GROUP BY OT2.csg_order_id) AS OT3 "
+ "ON OT1.csg_order_id = OT3.csg_order_id AND OT1.due_date = OT3.MaxDD");
Explanation:
Previously, in the first query, I was retrieving data from OpenTaskTable and then feeding it to the second query. Logically, in the second query also, I am just applying more filters over the retrieved data. At the end, we are trying to get all the attributes from OpenTaskTable only.
So, for this solution I simply used the first query, as the innermost query, and then selected MAX over the records grouped by csg_order_id. And, for the outermost query, just performed an inner join to get all matching csg_order_id records from OpenTaskTable.
I've to extract some specific data from Oracle DB. I'm using Java 8.
I have to consider 3 columns from a TABLE : flag | date_1 | date_2.
The flag can have values 1,2 or 3 (The flag values updates from 1->2->3 over a period of time or based on certain events).
Say for two dateTime values X and Y, I need extract all the rows from the table where the date value is between X and Y.
If flag value is 1 or 2 then date_1 must be between X & Y irrespective of date_2. But if flag value is 3 then date_2 must be between X & Y irrespective of date_1.
For this I created three different queries with different parameters as flag=1/flag=2/flag=3. But this seems to be very inefficient.
String sql1 = "SELECT new xxxx.xxxx.xxx.Java.class.xxx ("
+ "t.flag, t.date_1, t.date_2)"
+ "FROM Table t "
+ "WHERE t.flag = :flagValue1 "
+ "AND t.date_1 >= :X "
+ "AND t.date_1 < :Y ";
String sql2 = "SELECT new xxxx.xxxx.xxx.Java.class.xxx ("
+ "t.flag, t.date_1, t.date_2)"
+ "FROM Table t "
+ "WHERE t.flag = :flagValue2 "
+ "AND t.date_1 >= :X "
+ "AND t.date_1 < :Y ";
String sql3 = "SELECT new xxxx.xxxx.xxx.Java.class.xxx ("
+ "t.flag, t.date_1, t.date_2)"
+ "FROM Table t "
+ "WHERE t.flag = :flagValue3 "
+ "AND t.date_2 >= :X "
+ "AND t.date_2 < :Y ";
List<E> list1 = this.entityManger.createQuery(sql1, model.class)
.setParameter("1", flag1)
.setParameter("X", firstDateValue)
.setParameter("Y", secondDateValue)
.getResultList();
List<E> list2 = this.entityManger.createQuery(sql2, model.class)
.setParameter("2", flag2)
.setParameter("X", firstDateValue)
.setParameter("Y", secondDateValue)
.getResultList();
List<E> list3 = this.entityManger.createQuery(sql3, model.class)
.setParameter("3", flag3)
.setParameter("X", firstDateValue)
.setParameter("Y", secondDateValue)
.getResultList();
List<E> finalList = new ArrayList<>();
finalList.addAll(list1);
finalList.addAll(list2);
finalList.addAll(list3);
return finalList;
Is there any other way of doing this? What could be better (single)query for this ?
PS: I wonder if I can use Java 8's Lambda Functions for just filtering the values from the List. Any suggestions regarding this ?
Thanks for the help.
If i understand it correctly you actually have 2 input parameters X & Y (aka from/to Date). And you always want to query the values of all flags regarding the entered date. Therefore a query like this would be more efficient:
select new Java.class.name (t.flag, t.date_1, t.date_2) from Table t
where
(t.flag in (1,2) and t.date_1 >= :X and t.date_1 < :Y)
or
(t.flag = 3 and t.date_1 2= :X and t.date_2 < :Y)
This would reduce the whole thing to just one query ... may still be inefficient depending on the dataset.
I need to insert multiple rows (about 1 mln.) containing random numbers into a Postgresql database. This code generates one row with random numbers into a database. How can i make the statement loop itself for any amount of times?
Random rand = new Random();
for (int j=0;j < 1;j++);
stmt = c.createStatement();
String sql = "INSERT INTO COMPANY (ID,NAME,AGE,ADDRESS,SALARY) "
+ "VALUES ('" + rand.nextInt() + "', '" + rand.nextInt() + "', '" + rand.nextInt() + "', '" + rand.nextInt() + "'," +
" '" + rand.nextInt() + "')";
stmt.executeUpdate(sql);
stmt.close();
c.commit();
c.close();
You basically have two options to do that
Have the database do all the work
As suggested by #a_horse_with_no_name: use just one INSERT, and let the database compute all the random values:
INSERT INTO COMPANY
(ID
,NAME
,AGE
,ADDRESS
,SALARY)
SELECT
i
,random() * 10000 + 1
,random() * 80 + 1
,random() * 10000 + 1
,random() * 1000000 + 1
FROM
generate_series(1,1000000) i
This would be the usual way of filling a table with random values (to simulate data, for instance) when working with PostgreSQL. Note one thing: the ID column, assuming it is a PRIMARY KEY (i.e.: UNIQUE and NOT NULL) should never be assigned a random value, that could be repeated.
Have all the values computed by your program, but generate just one statement:
If, for some reason, the randomness of PostgreSQL is not good enough for your application, or you want to control through your program how the (pseudo)random values are generated, you could take advantage of the fact that you can have several rows stated in VALUES.
That is, the following statement is valid:
INSERT INTO some_table(a_column) VALUES (101), (102), (103), (104) ;
and would insert four rows into some_table.
You would change your program to generate values this way:
Random rand = new Random();
StringBuilder sql =
new StringBuilder("INSERT INTO COMPANY (ID,NAME,AGE,ADDRESS,SALARY) VALUES ;");
for (int j=0; j < 1000000; j++)
{
if (j) sql.append (",")
sql.append ("(" + j.toString() + /* ID should NOT be random() */
",'" + rand.nextInt().toString() + "'" + /* NAME */
",'" + rand.nextInt().toString() + "'" + /* AGE */
",'" + rand.nextInt().toString() + "'" + /* ADDRESS */
",'" + rand.nextInt().toString() + "'" + /* SALARY */
")") ;
}
stmt = c.createStatement();
stmt.executeUpdate(sql.toString());
stmt.close();
c.commit();
c.close();
NOTE 1: the SQL statement generated this way is not "dangerous" because you are completely controlling the data used to generate it. If you would use user input, or some information whose origin or format cannot be trusted, use PREPARED STATEMENTS, to avoid risks of SQL injection.
NOTE 2: Use a StringBuilder (not a String) to generate such a large String.
NOTE 3: As the SQL string can be too large to be handled by either the JDBC or the database itself (as pointed out by #dsp_user), it might be necessary to limit the number of iterations within the loop; and have a second loop over it (obviously, the use of the j variable should change in this scenario).
Trying to join 3 tables within a query returns an empty result. Strange enough, having one table removed (two tables join) returns some set. Here is what I do:
String sql = "SELECT\n" +
" tc.constraint_name, tc.table_name, kcu.column_name, \n" +
" ccu.table_name AS foreign_table_name,\n" +
" ccu.column_name AS foreign_column_name, constraint_type \n" +
"FROM \n" +
" information_schema.table_constraints AS tc \n" +
" JOIN information_schema.key_column_usage AS kcu\n" +
" ON tc.constraint_name = kcu.constraint_name\n" +
" JOIN information_schema.constraint_column_usage AS ccu\n" +
" ON ccu.constraint_name = tc.constraint_name\n" +
"WHERE constraint_type = 'FOREIGN KEY'";
List<Map<String, Object>> foreignTable1 = jdbcTemplate(getShardId(sku)).queryForList(sql);
Would always return an empty set.
Try using outer joins and check whether there are rows which don't have corresponding IDs so that the join removes the non-matching rows. Especially that you write, that two tables result in a non-empty result set seems to indicate, that the join with the third table does not result in matching rows of the result set of the first two.