I have a program in JAVA which creates a table in a database and then I insert rows in this table.
The table is created as below:
String sql = "CREATE TABLE IF NOT EXISTS weather (\n"
+ " city string,\n"
+ " temp real,\n"
+ " feels_like real,\n"
+ " temp_min real,\n"
+ " temp_max real,\n"
+ " pressure integer,\n"
+ " humidity integer\n"
+ ");";
When I add rows, I don't want to have duplicates for the field named "city".
So, for example, if I already have London with its data, I don't want to add it again, even though that all its data may have changed. I want to have it only once in my table.
I have this query for insertion :
String sql = "INSERT INTO weather VALUES(?,?,?,?,?,?,?);";
and I want to modify it so I don't insert city duplicates.
Can anyone help me please? Thanks!
If the version of SQLite you use is 3.24.0+ and there is a unique constraint for the column city, you can use upsert which gives you an option to do NOTHING or UPDATE the table if a unique constraint violation occurs.
In this case:
String sql =
"INSERT INTO weather VALUES(?,?,?,?,?,?,?) " +
"ON CONFLICT DO NOTHING";
if you try to insert a row with an existing city, the statement will fail without an error.
But if the new row contains up to date data for the other columns and you want the row updated, you can do this:
String sql =
"INSERT INTO weather VALUES(?,?,?,?,?,?,?) " +
"ON CONFLICT(city) DO UPDATE SET "
"temp = excluded.temp, " +
"feels_like = excluded.feels_like, " +
"temp_min = excluded.temp_min, " +
"temp_max = excluded.temp_max, " +
"pressure = excluded.pressure, " +
"humidity = excluded.humidity";
and the other 6 columns will be overwritten by the new values you supplied.
If there isn't a unique constraint defined for city and you don't want to or can't define one, then you can avoid inserting the same city twice with NOT EXISTS like this:
String sql =
"INSERT INTO weather SELECT ?,?,?,?,?,?,? " +
"WHERE NOT EXISTS (SELECT 1 FROM weather WHERE city = ?);
In this case you will have to pass in your Java code as an additional 8th parameter the value of the city again.
There is no way to do this in 'effectively standard SQL'*.
But, each individual DB engine does usually have some way of accomplishing this goal.
The concept is called merging or upserting - those are terms you can search the web for. Just search for 'how to postgres upsert' for example. It's called upsert because the more general application is: If some subset of the values I am inserting doesn't exist yet in the DB, INSERT a new row with this data. Otherwise, find the row with the same values for this subset, and then update all the other values with it. For example: "Find the student with ID 12345, and then change the name to 'Joe Bloggs'. If there is no row with that, then make it".
make ALL the values 'the key' and you've reduced your 'insert, ignore if it is already there' to a standard UPSERT.
In psql, you can do ON CONFLICT. searching for 'mysql upsert' gets you to blog posts that give you varying tactics depending on your exact needs, from using INSERT IGNORE (I advice against this, this ignores any and all errors, vs only ignoring the 'already in here' error only), ON DUPLICATE KEY UPDATE (better idea, this), or using REPLACE.
Similar blog posts will be found for any db engine you are using here.
*) Defined not as 'as per some version of the SQL standard', but defined as: 'works in the majority of existing DB engines'.
You can now use on conflict. This requires that you have a unique index/constraint on city but it is already defined as the primary key. Check.
insert into weather ( . . . )
values ( . . . )
on conflict (city) ignore;
SQLite also allows this shorthand:
insert or ignore into weather ( . . . )
values ( . . . );
Related
I am trying to delete the first & last row with Java HyperAPI which i used to optimise big data into .hyper file. in tableau server. Im not sure if this possible but based on the documentation, some of the use cases i read , its possible
based on normal sql query , we can delete the first row with
delete top(1) from tablename
Script shown below is working fine which is able to remove row based on where condition
long rowCountDeletedInCustomersTable = connection.executeCommand(
"DELETE FROM " + escapeName("Customer") +
"WHERE " + escapeName("Customer Name") + "=" + escapeStringLiteral("Dennis Kane")
).getAsLong();
however when i tried to delete the first with
long rowCountDeletedInCustomersTable = connection.executeCommand(
DELETE TOP(1) from " + escapeName("Customer")).getAsLong()
or
long rowCountDeletedInCustomersTable = connection.executeCommand(
DELETE FROM table WHERE ROWNUM = 1).getAsLong()
this will throw error, im not sure on which approach should i use
I am not really sure why you want to delete the "first" or "last" row from a Hyper file. Note that Hyper has no notion of "row order", so which row is considered to be the first/last row is somewhat random...
Hyper's SQL syntax follows Postgres' conventions instead of Microsoft's SQL dialect. DELETE TOP(1) is a Microsoft-specific syntax.
Hyper doesn't have a corresponding syntax. But assuming you have a column your_row_id which forms a key for your relationship, you can use
DELETE FROM tablename
WHERE your_row_id IN (SELECT your_row_id FROM tablename LIMIT 1)
i have problem with my table and exactly in ID column,
when i insert record>>the ID will increment by 1 automatically,
but the problem that when i delete old record
and insert new record the increment continue counting
and the ID of new record didn't take the ID of old record by sequence
;
my delete statment :
String Q="DELETE FROM EMPLOYEE ( ID , NAME) WHERE NAME='"+lst1.getSelectedValue()+"'";
stmt.execute(Q);
create statment:
stmt.execute("CREATE TABLE EMPLOYEE(ID INTEGER NOT NULL PRIMARY KEY"
+ " GENERATED ALWAYS AS IDENTITY(START WITH 1, INCREMENT BY 1)"
+ ",NAME varchar(50),BIRTHDAY varchar(50),BIRTHMONTH varchar(50)"
+ ",BIRTHYEAR varchar(50),SEX varchar(50),DEPARTMENT varchar(50))");}
insert statment:
String Query="INSERT INTO EMPLOYEE(NAME , BIRTHDAY , BIRTHMONTH , "
+ "BIRTHYEAR , SEX , DEPARTMENT) VALUES('"+txname.getText()+"','"
+ ""+compd.getSelectedItem()+"','"+compm.getSelectedItem()+"','"
+ ""+compy.getSelectedItem()+"','"+composx.getSelectedItem()+"','"
+ ""+txdep.getText()+"')";
stmt.execute(Query);
thanks very good firstly for answer and try help
You can solve that on the application side adopting the strategy of not really deleting the row, but adding a boolean field 'deleted', 0 if not deleted or 1 if deleted.
This in the case you want to avoid holes in the ID sequence.
Otherwise you live with the fact that there will be holes in the ID sequence. What is the problem with that?
By the way, what is the DB you are working with?
I read you comment. The point is that all the DBs append new records at the end of the table. So if you want to reuse IDs you have these possibilities:
make a piece of code to check if there is a free ID in the sequence
and use it in INSERT
make a piece of code to save free IDs somewhere and reuse them when you insert.
In other terms: you have to manage IDs directly. The way the DB manages them is:
Deleting a record produces a hole that will not be filled automatically
Adding a new record increment the last id
Regards
I imported a database from access to mysql but one of the table has a column name 'number of shares' with spaces but i have tried to change, replace and even drop the column name and failed. can any one be of help of how to go about it
String UpdateQuary = "UPDATE master SET trn_date=?,account_master=?,"
+ "title=?,first_name=?,sir_name=?,sex=?,birth_date=?,marital_status=?,"
+ "highest_educ_level=?,home_parish=?,centre=?,hiika=?,mobile1=?,"
+ "mobile2=?,email=?,kampala_residence=?,occupation=?,employer=?,"
+ "category_of_membership=?,"
+ "value_of_shares =?,number of shares=?";
You need to escape the column with backticks:
update master set `number of shares` = 100 where user_id = 3;
For example. I'd recommend just renaming the column if you can get away with that in your project.
Edit To rename, try this:
alter table master change `number of shares` number_of_shares int(11);
I have 5 rows in MS Access database one of them is Serial Number whose property is auto number I am trying to pass this query to the database to insert.
int s= sta.executeUpdate("INSERT INTO stockDB VALUES('"+name+"','"+size+"','"+quantity+"','"+price+"')");
In the database the Serial Number is the first column then the name,size,quantity and price.
When I am trying to do the insert i get this error:
[Microsoft][ODBC Microsoft Access Driver] Number of query values and destination fields are not the same.
I know i should put something in the first but what should i put it there?
I tried to put the Serial Number at the last but the error was the same.
What should i put in the query so that the sql accepts it but still genrates auto number in the database?
your sql query is wring
do like this
int s= sta.executeUpdate("INSERT INTO stockDB(name,size,quantity,price) VALUES('"+name+"','"+size+"','"+quantity+"','"+price+"')");
you need not to insert serial number manually because its auto increment but you have to specify the rest of the column names and values to be inserted and serial number value will be inerted automatically as its auto increment
try using different format of the query -
int s = sta.executeUpdate("insert into stockDB ('name', 'size', 'quantity', 'price') values('" + name + "','" + size + "','" + quantity + "','" + price + "')");
You need to specify Serial number field as AUTO_INCREMENT to automatically generate value for the field on inserting eecord in table.
Then specify field names in INSERT query and supply values.
What I have are 7 tables, one of which is a master list and the other 6 are archives. Also, the archives are on another database. I need to go through the archive tables and delete rows, by checking 3 different column IDs (top, middle, bottom) that are not listed in the master table, as they are not relevant anymore. My SQL statement is below. I don't have a way to test it yet, but since I am not very familiar with SQL I was hoping people could give a few tips.
String[] tables;
tables = new String[]{"archive1", "archive2", "archive3",
"archive4", "archive5", "archive6"};
String query;
Statement stmt;
String objs = "TOP AND MIDDLE AND BOTTOM";
while(i<tables.length){
//TODO: CONFIRM THE QUERY IS CORRECT
query = "DELETE FROM "+ tables[i] + " WHERE "+ objs +
"NOT IN(SELECT " + objs + " FROM DB.masterTable WHERE " +
objs + " IS NOT NULL)";
//IS NOT NULL may not be necessary
try{
//TODO: VERIFY CONNECTION IS CORRECT
stmt = this.DB2.createStatement();
stmt.executeUpdate(query);
}catch(SQLException x){
System.out.println("Failure in loop queries!");
}
i++;
}
}
In the tables there are many columns, but I am concerned with comparing the top, middle, and bottom IDs (together they are unique to each row, but e.g. top might have many of the same values). So like I said, if there isn't a row with the same TOP, MIDDLE, BOTTOM in the master table, OBJECTS, then that row can be deleted from the archive that has it listed. I tried to put everything in one query but maybe I need multiple?
My main questions are:
A) Is my query correct in any sense?
B) Since the tables are on 2 different databases how should I handle that?
Solution found:
query = "DELETE FROM "+ tables[i] +
" WHERE (TOP, MIDDLE, BOTTOM) NOT IN "+
"(SELECT TOP, MIDDLE, BOTTOM FROM DB1.DB.masterTable)";
Main problem became figuring out how to compare all 3 fields of each row at a time and accessing the DB tables
A) No. There are some fundamental errors in your query. If you expand out your query, where objs = "OBJ_ID_TOP AND OBJ_ID_MIDDLE AND OBJ_ID_BOTTOM"
query = "DELETE FROM "+ tables[i]
+ " WHERE OBJ_ID_TOP AND OBJ_ID_MIDDLE AND OBJ_ID_BOTTOM
NOT IN(SELECT OBJ_ID_TOP AND OBJ_ID_MIDDLE AND OBJ_ID_BOTTOM
FROM db1Connection.OBJECTS
WHERE OBJ_ID_TOP AND OBJ_ID_MIDDLE AND OBJ_ID_BOTTOM IS NOT NULL)";
This is not proper SQL... If we take a glance at the wiki page on the WHERE clause,
The proper syntax for writing SQL Where clause is
SELECT <> FROM table WHERE column operatorvalue
Use AND and OR to string up multiple column conditions in your WHERE clause.
Also, AND is not valid in a SELECT statement. If you want to combine multiple result sets, use UNION.
Something of the form (see below) is closer to what you need. (Note: it is not optimized by any means... just a demonstration)
EDIT Think I originally misunderstood what you were trying to do... but I think you want to delete from some_table, not master_table.
--DELETE --can swap out SELECT for DELETE when the selected results look right
SELECT s.*
FROM some_table s --this is table[i]
LEFT OUTER JOIN master_table mt --db1Connection.OBJECTS
on s.ID_TOP = mt.ID_TOP
AND s.ID_MIDDLE = mt.ID_MIDDLE
AND s.ID_BOTTOM = mt.ID_BOTTOM
WHERE mt.ID_TOP IS NULL
AND mt.ID_MIDDLE IS NULL
AND mt.ID_BOTTOM IS NULL
B) I can't help you with this question... someone with more DB2(?) chops can help you
You need to get the list of data to be deleted from the first DB.
Then go for deletion in the second DB
And, you just can't compare saying obj1 and obj2 and obj3 not in (some list), it should be like obj1 not in (somelist) and obj2 not in (somelist) and obj3 not is(whatever).
In this case, it would be a good idea to create a temp table in DB2 where the archive tables are, with data from the master table in DB1. Then, run queries like
delete from archive1 where col1 not in (select col_master from temp_table);