Delete rows with conflicting times using jdbc-odbc - java

I wasnt quite sure how to word the title so sorry about that. I am trying to load some start and stop schedule times into a database but sometimes a start and stop time for the same system will overlap such as one time may be 5:30 to 12:30 and then another time for the same system may be 8:30 to 10:30 I want to avoid inserting that data into the table.
I am using a jdbc and odbc bridge to do this all in a java program, when the user clicks generate schedules it reads all the schedule info from a text file, and then inserts it into the database. When the programs reads the times that are in between already existing times I want to skip doing the insert.
My Ideas so have to been to some how compared the end time i get from the text file with the MAX value of the times in the database and if its less than that value then skip this insert but I dont know how to tie the MAX value into an if statement. Another idea was after im done all the inserts then just delete the rows where the SCHEDULE_TIME is greater than the min value in the SCHEDULE_TIME column and the SCHEDULE_TIME is less than the max value in the SCHEDULE_TIME column.
here is an example of what the data in my table looks like:
SITE_ID ------- DEV_ID ------- SCHEDULE_TIME ------- VALUE_ENUM
---------------------------------------------------------------
1 3000 09:30:00 1
1 3000 15:30:00 0
1 3000 12:30:00 1
1 3000 13:30:00 0
1 3000 16:30:00 1
1 3000 18:30:00 0
the rows alternate from start top to stop time all the rows where VALUE_ENUM are 1 are start times and all the rows where VALUE_ENUM are 0 are stop times. Im trying to delete the time that falls between a other start and stop times in this case delete rows 3 and 4. Keep in mind this tables actually creates hundreds of rows from the text file so I can not just delete it manually, it would be best if I could find a way to just avoid inserting it.
Here is a copy of my current insert method, ignore all the extra columns I use, they are unrelated to the problem, they are just using so I add and delete for the correct systems.
private void Insert() throws SQLException
{
stmt = conn.createStatement();
String sqlStm = "update ARRAY_BAC_SCH_Schedule set SCHEDULE_TIME = {t '" + finalEnd + "'} WHERE SCHEDULE_TIME >= {t '" + finalStart + "'} AND" +
" SCHEDULE_TIME <= {t '" + finalEnd + "'} AND VALUE_ENUM = 0 AND DEV_ID = " + devID + " and INSTANCE = " + instanceNum;
int updateSuccess = stmt.executeUpdate(sqlStm);
if (updateSuccess < 1)
{
sqlStm = "insert into ARRAY_BAC_SCH_Schedule (SITE_ID, DEV_ID, INSTANCE, DAY, SCHEDULE_TIME, VALUE_ENUM, Value_Type) " +
" values (1, " + devID + ", " + instanceNum + ", " + day + ", {t '" + finalStart + "'}, 1, 'Unsupported')";
stmt.executeUpdate(sqlStm);
sqlStm = "insert into ARRAY_BAC_SCH_Schedule (SITE_ID, DEV_ID, INSTANCE, DAY, SCHEDULE_TIME, VALUE_ENUM, Value_Type) " +
" values (1," + devID + ", " + instanceNum + ", " + day + ", {t '" + finalEnd + "'}, 0, 'Unsupported')";
stmt.executeUpdate(sqlStm);
}
if(stmt!=null)
stmt.close();
}
I hope I explained this enough, sorry if the question is unclear.
I have also posted this question under sql tags to see if someone knows a way to do it with just sql.
Update: I had it working before by taking the last start and end time entering and then when I go to enter 2 new times I checked to see that the new start time was >= the previous one and that the new end time <= the previous end time and if they were I would skip the insert.
However I have had to make some changes to the program which I can no longer get the previous start/end time, my idea now is if I can select the last 2 times in the table and saved them to a variable on the java side and then do the same comparison I did before

I think the problem is with your design. If your text file is relying in the order you shouldn't be saving as is in the database.
I would have store that information in just one record. For example instead of having VALUE_ENUM and two records in the database you will just need one record with the following fields START_SCHEDULE_TIME and END_SCHEDULE_TIME. Now with that design you could just do a select like this:
select count(*) from ARRAY_BAC_SCH_Schedule where finalStart >=
START_SCHEDULE_TIME and finalEnd <= END_SCHEDULE_TIME
if the select returns 1 then you just skip and don't insert.

Is it fair to say that the problem area is characterised/identified by 2 or more consecutive start times? I suspect it is.
If that is the case then perhaps just load everything you have into the table, then parse the table in time order. Each time you encounter 2 consecutive start times you know you must delete 'this' start/end pair.
Of course if you encounter a THIRD start time in a row you know you have to delete 2 end times.
so in pseudocode - The dataset is ordered by Dev_Id, schedule_time, value_enum desc
int NestCount = 0;
int CurrDevId = 0;
for each record
{
// Optional DevId Logic Starts Here
if ThisRecord.DevId <> CurrDevId then
{
if NestCount <> 0
{
CurrDevId = 0;
RollBack;
Shriek("Cannot Proceed Because The Data Are Fubar");
}
else
{
CurrDevId = ThisRecord.DevId;
}
} // And Ends Here
if
CurrDevId <> 0 && // Optional DevId Logic
IsAStartRecord()
{
If NestCount > 0
{
DeleteThisRecord();
}
NestCount += 1;
}
else // Is an end record
{
NestCount -= 1;
If NestCount > 0
{
DeleteThisRecord();
}
}
}
If it is possible to implement this as a stored procedure I probably would.
Does that help ?

thanks for the help, but I ended up just doing a string replace on the : in the time and made it into a . then converted it to a double and saved that time into a temp variable and then the next time I had times for that system I checked if the start time was greater than the last start time and if the end time was less than the last one so if they fell between I could avoid adding, not 100% tested but it worked for the first system I tried

Related

Select * from SQLite TempTable not working properly

I have this small piece of code, the scope is:
In the outter while: I calculate a "min" number (selected from the tempTable)
In the inner while: I "Select * from (tempTable) where (some conditions)" (im completly sure there is more than 1 row that matches these conditions) and then i update the min in each row selected (whithin other aspects not relevant)
The inner while is conditioned by rs.next() which (as it does in other parts of my code) it should iterate through every row that matches the condition ("Select * from (tempTable) where (some conditions)")
Basically the program should work as: getting a "min" value, then proceed to update each row with equal "min" and "min" = "min" + 1. So in the next iteration of the outter while the "min" should be 1 more.
Instead, what it does is: get "min" value, then update ONLY the first row that matches that min value and goes back to the outter while(which calculates the min again). In the end, the output is rather the same and it kinda works, but I would really appreciate if it worked as I intended to match other aspects of the program.
I think the problem comes from doing a select * from a TEMPtable which for some reason returns only 1 row (i've been investigating but couldnt find other people with the same issue, so i don't really know). As I mentioned, there is other parts of my code where I do the same select * NORMALtable and the ResultSet.Next() works as intended.
while( total_tfgs > 0 ) {
int tfgs_round = 0;
min = prepareStatement.executeQuery("SELECT MIN("+ PROFESORES_COL_TFGS +") FROM TEMP_TABLA_PROFESORES WHERE " + PROFESORES_COL_OBLIGA + " = 'SÍ'").getInt(1);
ResultSet rs = prepareStatement.executeQuery("SELECT * FROM TEMP_TABLA_PROFESORES WHERE " + PROFESORES_COL_TFGS + " = '" + min + "' AND " + PROFESORES_COL_OBLIGA + " = 'SÍ'");
while(rs.next()) {
prepareStatement.executeUpdate("UPDATE TEMP_TABLA_PROFESORES SET PROFESORES_COL_TFGS = PROFESORES_COL_TFGS + 1 WHERE PROFESORES_COL_ID = '" + rs.getInt(1) + "'");
tfgs_round = tfgs_round + 1;
}
total_tfgs = total_tfgs - tfgs_ronda;
}
Here i place code where it works as i want it to work:
Statement statement = con.createStatement();
ResultSet rsA = statement.executeQuery("SELECT * FROM " + TABLA_ALUMNOS);
while(rsA.next()) {
String idA = String.valueOf(rsA.getInt("ALUMNOS_COL_ID"));
String dniA = rsA.getString("ALUMNOS_COL_DNI");
String nombreA = rsA.getString("ALUMNOS_COL_NOMBRE");
String dataA[] = {idA, dniA, nombreA};
DefaultTableModel tblModel = (DefaultTableModel) table_Alumnos.getModel();
tblModel.addRow(dataA);
table_Alumnos.setModel(tblModel);
}
PD: while redacting this i changed some variables to english (in the first code snipet) so it would be more legible(tfgs_round,total_tfgs), so if there is some misspell or something, thats not the problem. Please focus in the ResultSet select * from TEMP_TABLE (which i didnt change)
Thank you in advance for any help you can provide.
I would not call executeUpdate within the loop that is reading the ResultSet. That means you are using the statement for a second query while it is still involved in the first query. I would finish the first query entirely, close the ResultSet and then perform the update separately. If you really need to do an update while reading a ResultSet, I would build a new statement for it.

how to receive just one result from a query in a mysql database?

i´ve been using java to connect to a remote database in mysql, i´ve done a lot of diferents queries but today i´ve figured out that every time i wanted to look for a result, i have been always storing the result/s in a resulset,although in some cases my queries just have to return 0 or 1 result,that means that is not possible to receive an array of registers that meet the querie, so what kind of variable should i use to store JUST ONE RESULT?
Below i will post a portion of my code that describe the situation, it have to be understood that in the table "tareas", every register have a DIFFERENT title, like a PK.
Thanks in advance...
ps = c.prepareStatement("SELECT * FROM tareas WHERE titulo='" + title + "'");
rr = ps.executeQuery();
while (rr.next()) {
JOptionPane.showMessageDialog(null, "Titulo: " + rr.getString("titulo") + newline +
"Creador: " + rr.getString("nombre") + newline +
"Receptor: " + rr.getString("receptor") + newline +
"Tarea: " + nuevacadena(rr.getString("tarea")) + newline +
"fecha de creación:" + lafecha(rr.getString("fecha")));
}
Add a LIMIT; without that the JDBC driver may pre-fetch more than one row regardless of option 2 (which you can also do). That is,
ps = c.prepareStatement("SELECT * FROM tareas WHERE titulo='" + title + "' LIMIT 1");
and then change (for option 2)
while (rr.next())
to
if (rr.next())
Also, since you are using a PreparedStatement, you should bind your parameters instead of writing them literally into the query; for example,
ps = c.prepareStatement("SELECT * FROM tareas WHERE titulo=? LIMIT 1");
ps.setString(1, title);

how to split records returned from a query into sets of 1000 via jdbc

I have a source and a target database and I need to check the count in both, is it same or not.
I fetch a column from source database via below queries:
DMS_Arr[0] = "select count(distinct eai_src_pk) from document_id_creation where eai_entry_date > (trunc(sysdate-1) + 00/24) and eai_entry_date < (trunc(sysdate) + 00/24)";
DMS_Arr[1] = "select distinct eai_src_pk from document_id_creation where eai_entry_date > (trunc(sysdate-1) + 00/24) and eai_entry_date < (trunc(sysdate) + 00/24)";
Now I store the output of DMS_Arr[1] into a variable "targetPk" separated by commas and use it in my JDBC query to check the count at target side via the below query.
ERP_Arr[0] ="select count(distinct eai_src_pk) from xxindus.XXINDUS_ERP_OBRM_PYMT_CNDN_T where eai_src_pk in (" + targetPk + ")" + " and eai_entry_date > (trunc(sysdate-1) + 00/24)";
However, the problem is that the records in variable targetPk could be 1000, 10000 or 150000 and database is able to handle only 1000 at a time. How can I make my code handle this and automatically split them into sets of 1000 so that JDBC query does not throw any error. Then I need to store all these values returned into a string variable separated by commas and check the count.

Oracle SQL Merge will not execute over Statement

I have a table with four columns, this is how it looks like. I would call it T_BPR_KPI_MONTHLY_VALUES
KPI_NAME_SHORT_S | MONTH_N | YEAR_N | VALUE_N
-----------------------------------------------
MY_KPI_1 | 1 | 2015 | 99.87
MY_KPI_2 | 1 | 2015 | 97.62
... | 1 | 2015 | ...
MY_KPI_1 | 2 | 2015 | ...
... | ... | 2015 | ...
Each kpi represents a measurement and each of them has daily values which are saved in another table called T_BPR_KPI_DY. My goal is to calculate and save monthly values of each KPI.
It is possible that on the certain day, daily values for some kpis are still missing and in order to precisely calculate monthly values I must be able to replace exisisting values in the database as well as insert new etries for the future months and years.
I tought that oracle sql merge operation would be good choice for this task. The idea is to check whether an entry already exists and if so than to update its value and if not to insert new one.
This is how the query looks like
MERGE INTO T_BPR_KPI_MONTHLY_VALUE A
USING( SELECT 'MY_KPI_1' AS KPI_NAME_SHORT_S, 1 AS MONTH_N, 2014 AS YEAR_N FROM DUAL ) B
ON ( A.KPI_NAME_SHORT_S = B.KPI_NAME_SHORT_S )
WHEN MATCHED THEN
UPDATE SET VALUE_N = ( select AVG(MY_KPI_1) from T_BPR_KPI_DY where DAY_D between '01.01.2014' AND '31.01.2014')
WHEN NOT MATCHED THEN
INSERT (KPI_NAME_SHORT_S, MONTH_N, YEAR_N, VALUE_N) VALUES ('MY_KPI_1', 1, 2014, ( select AVG(MY_KPI_1) from T_BPR_KPI_DY where DAY_D between '01.01.2014' AND '31.01.2014') )
I tought that calculating avg monthly values on the fly is not a bad idea, so as you can see I have another select query which only calculates avg monthy value for the specific kpi. I am not sure if this is a best practic solution but it works fine when I execute this query in oracle sql developer tool. however when I try to execute it from the app it does not work.
This is how the method looks like
public static void storeValuesToDb(ArrayList<String> kpiNames) throws SQLException {
Connection conn = getOracleJDBCConnection_DASH();
int currentYear = cal.get(Calendar.YEAR);
int startYear = cal.get(Calendar.YEAR) - 1;
for (String kpiName : kpiNames) {
for (int i = startYear; i <= currentYear; i++) {
for (int j = 0; j < 12; j++) {
try {
String myMergeSQL = ""
+ "MERGE INTO T_BPR_KPI_MONTHLY_VALUE A "
+ "USING( SELECT '" + kpiName + "' AS KPI_NAME_SHORT_S, " + (j + 1) + " AS MONTH_N, " + i + " AS YEAR_N FROM DUAL ) B ON ( A.KPI_NAME_SHORT_S = B.KPI_NAME_SHORT_S ) "
+ "WHEN MATCHED THEN "
+ "UPDATE SET VALUE_N = ( select AVG(" + kpiName + ") from T_BPR_KPI_DY where DAY_D between '" + getFirstDateOfMonth(j, i) + "' AND '" + getLastDateOfMonth(j, i) + "') "
+ "WHEN NOT MATCHED THEN "
+ "INSERT (KPI_NAME_SHORT_S, MONTH_N, YEAR_N, VALUE_N) VALUES ('" + kpiName + "', " + (j + 1) + ", " + i + ", ( select AVG(" + kpiName + ") from T_BPR_KPI_DY where DAY_D between '" + getFirstDateOfMonth(j, i) + "' AND '" + getLastDateOfMonth(j, i) + "') )";
System.out.println(myMergeSQL);
Statement stmt_dash = conn.createStatement();
stmt_dash.executeUpdate(myMergeSQL);
conn.commit();
stmt_dash.close();
} catch (SQLException ex) {
conn.close();
}
}
}
}
conn.close();
}
In terminal it prints out only the first merge sql. It neither finishs the operation nor throws an exception. It blocks somehow and in the db happens also nothing. It could be possible that my merge query is not correct or that it is not possible to execute this kind of operation with statement object. If someone is able to see what cases this issue, please help.
Thx in advance
I would start by reformulating your merge query and solve some issues:
the USING part of a MERGE actually means your "source of raw data". You are using a select from dual with hardcoded values. Here you should select all KPIs and also calculate the Average by KPI. Compose your query that selects all KPIs with their coresponding VALUE_N and use it in the USING part
when matched then UPDATE SET use the values from "source of raw data" which is alias B in your code, not compute on inside the UPDATE clause.
when not matched then INSERT VALUES - again, use values from "source of raw data" which is alias B in your code, do not try to compute the VALUE_N inside the insert - well at least not in that manner I think this is your querys main issue.
MERGE INTO xxx A using () B you gave 2 aliases to your tables but down the line inside the WHEN MATCHED or NOT you are not using the alias. This can raise problems if A and B have similar named columns.
An example of how I use merge in production:
Merge into Destination, using a select from a table Source (inside the select from source you can also add other computations obviously, in your case the average)
T_REPORT_DAILY_SNAPSHOT_2G should be in your code the select kpis name, value and average or whatever you need on INSERT and UPDATE
MERGE INTO T_CELLS_2G dest
USING (SELECT DISTINCT *
FROM T_REPORT_DAILY_SNAPSHOT_2G) src
ON (dest.lac = src.lac and dest.cell_id = src.cell_id)
WHEN MATCHED THEN
UPDATE SET
dest.cell_name = src.cell_name,
dest.loc_code = src.loc_code,
dest.site_code = src.site_code,
dest.rac = src.rac
WHEN NOT MATCHED THEN
INSERT (dest.cell_name,
dest.loc_code,
dest.site_code,
dest.lac,
dest.cell_id,
dest.rac)
VALUES (src.cell_name,
src.loc_code,
src.site_code,
src.lac,
src.cell_id,
src.rac);
Hope this helps in some way.

Hibernate Criteria - get count of subselect

I would like to count the number of events that fulfill a certain condition. If the row count is less than a million I would like to get the actual number. If it is more than a million I do not need to know the exact number and it is ok to return the count as 1 million.
I thought about this query
select count(*) from (select id from events where x=10 limit 1000000) a
How can it be done Detached Criteria / sub criteria?
Is there a better way of doing it other than the above sql? I'm using postgresql 9.3
That query won't perform better than a regular count, so try this instead:
long count = ((Number)
session.createCriteria(Event.class)
.setProjection(Projections.rowCount())
.add(Restrictions.eq("x", 10))
.uniqueResult()).longValue();
long countLimit = Math.min(count, 1000000);
As I understood
You have to count some recode if it is >1000000 it should show 1 Million +
else exact count.
For this you cat try this query
String t;
t = (String) session.createQuery(
"select case when count(*)>1000000 "
+ "then '1Million +' "
+ "else count(*) "
+ "end "
+ "from events").uniqueResult();
session.getTransaction().commit();
System.out.println("size is " + t);
Use CASE [ WHEN {test_conditional} THEN {match_result} ]* ELSE {miss_result} END
https://docs.jboss.org/hibernate/orm/4.3/devguide/en-US/html/ch11.html#d5e3280

Categories

Resources