SQLite If Column Exists - database

I was wondering if there is a nice IF NOT EXISTS for checking columns and indexes in SQLite, or do I need to bring back the entire database schema and validate against that?

There is a system catalog table called sqlite_master that you can use to check index (or other) names:
SELECT name FROM sqlite_master WHERE type='index' ORDER BY name;
You can use a pragma to get the indexed columns:
PRAGMA index_info(index-name);
And this one to get the column names for a table:
PRAGMA table_info(table-name);

Yes the following syntax is supported in sqlite: CREATE INDEX IF NOT EXISTS ...
See here
To check existence of a column you could simply try to do something like SELECT col from TABLE. If it does not return an error your table contains col.

In SQLite, If you want to check whether your column/field exist in your table or not....try this answer work for me...
https://stackoverflow.com/a/28146506/3126569
Cursor res = db.rawQuery("PRAGMA table_info("+tableName+")",null);
int value = res.getColumnIndex(fieldName);

This is how I do it,
INSERT INTO AUDITEVENT (CODE, DESCRIPTION, AUDITEVENTPK)
SELECT 'value1', 'value2', 'value3'
WHERE NOT EXISTS (SELECT 1 FROM AUDITEVENT WHERE CODE = 'value1')
In my IDConneciton, I have a method called ProcessCommandText to update the query from SQL Server syntax to SQLite only.
This is the implementation of that method
public string ProcessSqlText(string text)
{
var result = text.Replace("SET ANSI_NULLS ON", "").
Replace("SET ANSI_NULLS ON", "").
Replace(" ASC)", ")").
Replace("TOP 100", "TOP(100)").
Replace("TOP 1", "TOP(1)").
Replace(" VARCHAR", " NVARCHAR").
Replace(" CHAR", " NCHAR").
Replace(" TEXT", " NTEXT").
Replace("WITH ( IGNORE_DUP_KEY = OFF)", "").
Replace("SET QUOTED_IDENTIFIER ON", "").
Replace("SET ANSI_PADDING ON", "").
Replace("SET ANSI_PADDING OFF", "").
Replace("SET ANSI_WARNINGS ON", "").Trim(' ').
Replace("WITH NOCHECK", "").
Replace("(nolock)", "").
Replace("CREATE CLUSTERED INDEX", "CREATE NONCLUSTERED INDEX").
Replace("CREATE UNIQUE CLUSTERED INDEX", "CREATE UNIQUE NONCLUSTERED INDEX").
Replace("[dbo].", "").
ToUpper().
Replace("NEWID()", "'" + Guid.NewGuid().ToString() + "'"). // NEWID() is not supported
Replace("GO", ""); // GO is not supported
if (result.Contains("TOP(100)"))
{
result = result.Replace("TOP(100)", "");
result += " LIMIT 100";
}
if (result.Contains("TOP(1)"))
{
result = result.Replace("TOP(1)", "");
result += " LIMIT 1";
}
if (result.Contains("DATEPART"))
{
result = result.Replace("DATEPART", "strftime");
result = result.Replace("minute", "'%M'");
result = result.Replace("day", "'%d'");
result = result.Replace("month", "'%m'");
result = result.Replace("year", "'%Y'");
}
result = TransformIfNotExistsQueriesToSqlLite(result);
return result;
}
private string TransformIfNotExistsQueriesToSqlLite(string query)
{
var ifNotExistsRegEx = #"(IF NOT EXISTS\s+)\(+.+\)+\r+\n+INSERT+";
var m = Regex.Match(query, #"(IF NOT EXISTS\s+)\(+.+\)+\r+\n+INSERT+", RegexOptions.IgnoreCase);
if (m.Groups.Count > 0 && m.Groups[0].Value.Contains("IF NOT EXISTS"))
{
var conditionalStatement = m.Groups[0].Value;
var newQuery = query.Replace(conditionalStatement, " INSERT ");
conditionalStatement = conditionalStatement.ToUpper().Replace("IF", "WHERE").Replace("INSERT", "");
newQuery = Regex.Replace(newQuery.ToUpper(), #"VALUES\s+\(+", " SELECT ");
var lastIndexOfClosingBracket = newQuery.LastIndexOf(')');
newQuery = newQuery.Substring(0, lastIndexOfClosingBracket);
return newQuery + " " + conditionalStatement;
}
return query;
}

Why dont you just catch the exception? For example:
try{
db.execSQL("ALTER TABLE ACCOUNT_ENTRY ADD COLUMN ID_CONCEPT NUMBER(10)");
}catch(Exception e){
System.out.println(e);
}

Related

Snowflake Stored Procedure For Loop

i'm working with Snowflake,
i created this Stored Procedure, it's purpose is to do the following steps:
extract the relevant 'application_id' values from the SQL query
use a FOR loop over a SQL query, with the 'application_id' values that i extracted
in step 1, and delete the relevant rows from the target table.
when i call the Stored Procedure, it runs without errors, but it doesn't do anything ( the relevant records are not been deleted).
i added my SP code,
please let me know if you see any syntax / logic errors,
thanks
CREATE OR REPLACE PROCEDURE DWH.sp_testing()
RETURNS string
LANGUAGE javascript
strict
EXECUTE AS owner
AS
$$
try
{
var application_list = ` SELECT application_id
FROM PUBLIC.my_source_table_name
WHERE my_flag = 1
`
var query_statement = snowflake.createStatement({sqlText: application_list});
var application_list_result = query_statement.execute();
for (i = 1; i <= query_statement.getRowCount(); i++)
{
application_list_result.next()
application_id = application_list_result.getColumnValue(1)
var delete_daily_records = `
DELETE FROM PUBLIC.my_target_table_name AS target
WHERE target.application_id = ${application_id}
`
snowflake.execute({sqlText: delete_daily_records});
}
}
catch (err)
{
throw "Failed: " + err;
}
$$
;
CALL DWH.sp_testing();
Are you sure your query is returning data? Also are you sure the target table has data matching your DELETE statement?
The following test works for me using your stored procedure:
select count(*) from citibike_trips where end_station_id=6215;
returns: 14565
Now, I created your stored proc:
CREATE OR REPLACE PROCEDURE sp_testing()
RETURNS string
LANGUAGE javascript
strict
EXECUTE AS owner
AS
$$
try
{
var application_list = `SELECT end_station_id
FROM citibike_trips
WHERE end_station_id=6215 limit 10
`
var query_statement = snowflake.createStatement({sqlText: application_list});
var application_list_result = query_statement.execute();
for (i = 1; i <= query_statement.getRowCount(); i++)
{
application_list_result.next()
end_station_id = application_list_result.getColumnValue(1)
var delete_daily_records = `
DELETE FROM citibike_trips AS target
WHERE target.end_station_id = ${end_station_id}
`
snowflake.execute({sqlText: delete_daily_records});
}
}
catch (err)
{
throw "Failed: " + err;
}
$$
;
Run it:
CALL SP_TESTING();
Shows NULL as result (expected since it is not returning anything).
But then when I check the table again:
select count(*) from citibike_trips where end_station_id=6215;
returns: 0

Violation of PRIMARY KEY constraint. Cannot insert duplicate key in object

I inherited a project and I'm running into a SQL error that I'm not sure how to fix.
On an eCommerce site, the code is inserting order shipping info into another database table.
Here's the code that is inserting the info into the table:
string sql = "INSERT INTO AC_Shipping_Addresses
(pk_OrderID, FullName, Company, Address1, Address2, City, Province, PostalCode, CountryCode, Phone, Email, ShipMethod, Charge_Freight, Charge_Subtotal)
VALUES (" + _Order.OrderNumber;
sql += ", '" + _Order.Shipments[0].ShipToFullName.Replace("'", "''") + "'";
if (_Order.Shipments[0].ShipToCompany == "")
{
sql += ", '" + _Order.Shipments[0].ShipToFullName.Replace("'", "''") + "'";
}
else
{
sql += ", '" + _Order.Shipments[0].ShipToCompany.Replace("'", "''") + "'";
}
sql += ", '" + _Order.Shipments[0].Address.Address1.Replace("'", "''") + "'";
sql += ", '" + _Order.Shipments[0].Address.Address2.Replace("'", "''") + "'";
sql += ", '" + _Order.Shipments[0].Address.City.Replace("'", "''") + "'";
sql += ", '" + _Order.Shipments[0].Address.Province.Replace("'", "''") + "'";
sql += ", '" + _Order.Shipments[0].Address.PostalCode.Replace("'", "''") + "'";
sql += ", '" + _Order.Shipments[0].Address.Country.Name.Replace("'", "''") + "'";
sql += ", '" + _Order.Shipments[0].Address.Phone.Replace("'", "''") + "'";
if (_Order.Shipments[0].ShipToEmail == "")
{
sql += ",'" + _Order.BillToEmail.Replace("'", "''") + "'";
}
else
{
sql += ",'" + _Order.Shipments[0].ShipToEmail.Replace("'", "''") + "'";
}
sql += ", '" + _Order.Shipments[0].ShipMethod.Name.Replace("'", "''") + "'";
sql += ", " + shippingAmount;
sql += ", " + _Order.ProductSubtotal.ToString() + ")";
bll.dbUpdate(sql);
It is working correctly, but it is also outputting the following SQL error:
Violation of PRIMARY KEY constraint 'PK_AC_Shipping_Addresses'. Cannot insert
duplicate key in object 'dbo.AC_Shipping_Addresses'. The duplicate key value
is (165863).
From reading similar questions, it seems that I should declare the ID in the statement.
Is that correct? How would I adjust the code to fix this issue?
I was getting the same error on a restored database when I tried to insert a new record using the EntityFramework. It turned out that the Indentity/Seed was screwing things up.
Using a reseed command fixed it.
DBCC CHECKIDENT ('[Prices]', RESEED, 4747030);GO
I'm pretty sure pk_OrderID is the PK of AC_Shipping_Addresses
And you are trying to insert a duplicate via the _Order.OrderNumber?
Do a
select * from AC_Shipping_Addresses where pk_OrderID = 165863;
or select count(*) ....
Pretty sure you will get a row returned.
It is telling you that you are already using pk_OrderID = 165863 and cannot have another row with that value.
if you want to not insert if there is a row
insert into table (pk, value)
select 11 as pk, 'val' as value
where not exists (select 1 from table where pk = 11)
What is the value you're passing to the primary key (presumably "pk_OrderID")? You can set it up to auto increment, and then there should never be a problem with duplicating the value - the DB will take care of that. If you need to specify a value yourself, you'll need to write code to determine what the max value for that field is, and then increment that.
If you have a column named "ID" or such that is not shown in the query, that's fine as long as it is set up to autoincrement - but it's probably not, or you shouldn't get that err msg. Also, you would be better off writing an easier-on-the-eye query and using params. As the lad of nine years hence inferred, you're leaving your database open to SQL injection attacks if you simply plop in user-entered values. For example, you could have a method like this:
internal static int GetItemIDForUnitAndItemCode(string qry, string unit, string itemCode)
{
int itemId;
using (SqlConnection sqlConn = new SqlConnection(ReportRunnerConstsAndUtils.CPSConnStr))
{
using (SqlCommand cmd = new SqlCommand(qry, sqlConn))
{
cmd.CommandType = CommandType.Text;
cmd.Parameters.Add("#Unit", SqlDbType.VarChar, 25).Value = unit;
cmd.Parameters.Add("#ItemCode", SqlDbType.VarChar, 25).Value = itemCode;
sqlConn.Open();
itemId = Convert.ToInt32(cmd.ExecuteScalar());
}
}
return itemId;
}
...that is called like so:
int itemId = SQLDBHelper.GetItemIDForUnitAndItemCode(GetItemIDForUnitAndItemCodeQuery, _unit, itemCode);
You don't have to, but I store the query separately:
public static readonly String GetItemIDForUnitAndItemCodeQuery = "SELECT PoisonToe FROM Platypi WHERE Unit = #Unit AND ItemCode = #ItemCode";
You can verify that you're not about to insert an already-existing value by (pseudocode):
bool alreadyExists = IDAlreadyExists(query, value) > 0;
The query is something like "SELECT COUNT FROM TABLE WHERE BLA = #CANDIDATEIDVAL" and the value is the ID you're potentially about to insert:
if (alreadyExists) // keep inc'ing and checking until false, then use that id value
Justin wants to know if this will work:
string exists = "SELECT 1 from AC_Shipping_Addresses where pk_OrderID = " _Order.OrderNumber; if (exists > 0)...
What seems would work to me is:
string existsQuery = string.format("SELECT 1 from AC_Shipping_Addresses where pk_OrderID = {0}", _Order.OrderNumber);
// Or, better yet:
string existsQuery = "SELECT COUNT(*) from AC_Shipping_Addresses where pk_OrderID = #OrderNumber";
// Now run that query after applying a value to the OrderNumber query param (use code similar to that above); then, if the result is > 0, there is such a record.
To prevent inserting a record that exist already. I'd check if the ID value exists in the database. For the example of a Table created with an IDENTITY PRIMARY KEY:
CREATE TABLE [dbo].[Persons] (
ID INT IDENTITY(1,1) PRIMARY KEY,
LastName VARCHAR(40) NOT NULL,
FirstName VARCHAR(40)
);
When JANE DOE and JOE BROWN already exist in the database.
SET IDENTITY_INSERT [dbo].[Persons] OFF;
INSERT INTO [dbo].[Persons] (FirstName,LastName)
VALUES ('JANE','DOE');
INSERT INTO Persons (FirstName,LastName)
VALUES ('JOE','BROWN');
DATABASE OUTPUT of TABLE [dbo].[Persons] will be:
ID LastName FirstName
1 DOE Jane
2 BROWN JOE
I'd check if i should update an existing record or insert a new one. As the following JAVA example:
int NewID = 1;
boolean IdAlreadyExist = false;
// Using SQL database connection
// STEP 1: Set property
System.setProperty("java.net.preferIPv4Stack", "true");
// STEP 2: Register JDBC driver
Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
// STEP 3: Open a connection
try (Connection conn1 = DriverManager.getConnection(DB_URL, USER,pwd) {
conn1.setAutoCommit(true);
String Select = "select * from Persons where ID = " + ID;
Statement st1 = conn1.createStatement();
ResultSet rs1 = st1.executeQuery(Select);
// iterate through the java resultset
while (rs1.next()) {
int ID = rs1.getInt("ID");
if (NewID==ID) {
IdAlreadyExist = true;
}
}
conn1.close();
} catch (SQLException e1) {
System.out.println(e1);
}
if (IdAlreadyExist==false) {
//Insert new record code here
} else {
//Update existing record code here
}
Not OP's answer but as this was the first question that popped up for me in google, Id also like to add that users searching for this might need to reseed their table, which was the case for me
DBCC CHECKIDENT(tablename)
There could be several things causing this and it somewhat depends on what you have set up in your database.
First, you could be using a PK in the table that is also an FK to another table making the relationship 1-1. IN this case you may need to do an update rather than an insert. If you really can have only one address record for an order this may be what is happening.
Next you could be using some sort of manual process to determine the id ahead of time. The trouble with those manual processes is that they can create race conditions where two records gab the same last id and increment it by one and then the second one can;t insert.
Third, you query as it is sent to the database may be creating two records. To determine if this is the case, Run Profiler to see exactly what SQL code you are sending and if ti is a select instead of a values clause, then run the select and see if you have due to the joins gotten some records to be duplicated. IN any even when you are creating code on the fly like this the first troubleshooting step is ALWAYS to run Profiler and see if what got sent was what you expected to be sent.
Make sure if your table doesn't already have rows whose Primary Key values are same as the the Primary Key Id in your Query.

Service Stack OrmLite and Identity_Insert

When using Service Stack OrmLite how do you insert identity values exactly?
For instance in SQL Server when Identity_Insert is turned on for a table the identity value will be inserted exactly as specified and will not instead be auto generated.
Do not decorate your primary key with the [AutoIncrement] attribute. If you do so, then OrmLite will leave that column name and value out of the INSERT statement.
Issue the SET IDENTITY_INSERT statement. Make sure to let OrmLite build the table name for you, taking into account any [Schema] and [Alias] attributes.
For example:
public void InsertAll(IEnumerable<TTable> set)
{
const string identity = "SET IDENTITY_INSERT {0} {1}";
var schema = typeof(TTable).FirstAttribute<SchemaAttribute>();
var tableName = typeof(TTable).FirstAttribute<AliasAttribute>();
var qualified = (schema == null ? "dbo" : schema.Name) + "." +
(tableName == null ? typeof(TTable).Name : tableName.Name);
using (var db = _dbConnectionFactory.OpenDbConnection())
{
try
{
db.ExecuteSql(string.Format(identity, qualified, "ON"));
db.InsertAll(set);
}
finally
{
db.ExecuteSql(string.Format(identity, qualified, "OFF"));
}
});
}

Add value into database plus 1

In my database I have:
Row ID - Driver ID - Log ID.
Row ID is unique and auto-increments. What I want is for the Log ID to be unique for each row that has that Driver ID.
For example say a row is inserted with Driver ID 1 I want that row to have a Log ID of 1 but the next time a row is inserted with Driver ID 1 I want it to have a Log ID of 2.
How can I achieve this?
By way for database i am using PHPMyAdmin.
----------------Edit----------------------
This is what i have in my PHP now, but it says:
On the webpage: Incorrect integer value: '' for column 'FinesCost' at row 1
And i dump the variables and get this: string(2) "16" string(2) "16" string(2) "16" so i dont understand why it is saying incorrect integer value and why it is saying they are undefines because they are very clearly defined.
In the PHP error log: [19-Jul-2013 10:44:18 Europe/Minsk] PHP Notice: Undefined variable: FinesCostP‌ost2 in C:\inetpub\wwwroot\hosting\Dan\JWT\drivers-log-send.php on line 336
[19-Jul-2013 10:44:18 Europe/Minsk] PHP Notice: Undefined variable: TravelExpensesPo‌​st2 in C:\inetpub\wwwroot\hosting\Dan\JWT\drivers-log-send.php on line 336
///PHP TO INSERT DRIVER'S BANK DETAILS INTO BANK DATABASE
session_start();
$host=""; // Host name
$username=""; // Mysql username
$password=""; // Mysql password
$db_name=""; // Database name
$tbl_name="jwtdriversbank"; // Table name
$un = "";
$usrname = "";
$usrpass = "";
$userID = "";
mysql_connect("$host", "$username", "$password")or die("cannot connect");
mysql_select_db("$db_name")or die("cannot select DB");
if(isset ($_SESSION['usrName']))
{
$usrname = $_SESSION['usrName'];
}
else
{
echo "4";
}
//var_dump ($usrname);
if(isset ($_SESSION['usrPass']))
{
$usrpass = $_SESSION['usrPass'];
}
else
{
echo "5";
}
$sql="SELECT * FROM jwtdrivers WHERE username='$usrname' and password='$usrpass'";
$result=mysql_query($sql);
$rows=mysql_fetch_array($result);
$userID = $rows['id'];
//var_dump ($userID);
if($userID == "")
{
echo "3";
}
else
{
$TotalProfitPost = $TotalProfit;
$LateFeePost = $LateFee;
$FinesCostPost2 = $FinesCost;
$TravelExpensesPost2 = $TravelExpenses;
$FuelCostPost = $FuelCost;
$CargoDamagePost = $CargoDamage;
$TruckDamagePost = $TruckDamage;
var_dump ($TotalProfitPost);
var_dump($FinesCostPost2);
var_dump($TravelExpensesPost2);
$sql="INSERT INTO jwtdriversbank2 (DriverID, LogID, TotalProfit, LateFee, FinesCost, TravelExpenses, FuelCost, CargoDamage, TruckDamage) VALUES ('$userID', COALESCE((Select MAX(LogID) from jwtdriversbank2 tab2 where tab2.DriverID = '$userID'),0)+1,'$TotalProfitPost','$LateFeePost', '$FinesCostP‌ost2' , '$TravelExpensesPo‌​st2' ,'$FuelCostPost','$CargoDamagePost','$TruckDamagePost')";
$result = mysql_query($sql);
if($result)
{
}
else
{
die(mysql_error());
}
}
Add a primary key for the two columns.
It should do the trick.
Look at this link for help
ALTER TABLE table_name
ADD CONSTRAINT pk_DriverID PRIMARY KEY (DriverID,LogID)
Do not forget to drop the first primary key because you will not need it no more.
EDIT : COMPLETE WITH THE OTHER ANSWER
Here is the code to insert your data.
Insert into <table_name>
values p_RowID, p_DriverID, COALESCE((Select MAX(Log_id) from <table_name> tab2 where tab2.Driver_id = p_DriverID),0)+1;
That should close the question.
You did not defined variable because PHP can't read them.
I opened your program inside VIM editor and I found "<200c>" char inside $FineCostPost2 in the SQL query. You have to change it to make it work.
A quick solution would be to use a subquery to find the maximum log (last log id) then increment it, something like this
Insert into <table_name>
values p_RowID, p_DriverID, COALESCE((Select MAX(Log_id) from <table_name> tab2 where tab2.Driver_id = p_DriverID),0)+1;
Here p_RowID and p_DriverID are the values you pass to insert into your table. The Coalesce function would check the given value and if it is NULL then it would replace it with the second parameter, in this case 0

Handle database error in CodeIgniter [Error Number: 1062]

I'm getting the following error while executing database query:
A Database Error Occurred
Error Number: 1062
Duplicate entry '1' for key 'PRIMARY'
UPDATE tbl_galeri SET id_galeri = '1', galeri_kat_id = '1', nama = 'Elyza Okiliyandass', foto = 0, deskripsi = 'Elyza Okiliyanda'
Filename: C:\xampp\htdocs\indonesiausher\system\database\DB_driver.php
Line Number: 330
Controller:
$pilih['id_galeri'] = $this->uri->segment(3);
$dt_galeri = $this->app_model->getSelectedData("tbl_galeri",$pilih);
foreach($dt_galeri->result() as $db)
{
$bc['id_galeri'] = $db->id_galeri;
$bc['galeri_kat_id'] = $db->galeri_kat_id;
$bc['nama'] = $db->nama;
$bc['foto'] = $db->foto;
$bc['deskripsi'] = $db->deskripsi;
$bc['stts'] = "edit";
}
$this->load->view('backend/gallery/bg_input_usher',$bc);
}
Model:
public function getSelectedData($table,$data)
{
return $this->db->get_where($table, $data);
}
How to handle this error?
Thanks..
Once try by removing the id_galeri like below in UPDATE Query
UPDATE tbl_galeri SET galeri_kat_id = '1', nama = 'Elyza Okiliyandass', foto = 0, deskripsi = 'Elyza Okiliyanda' WHERE id_galeri = '1'
EDIT
May be you don't need to update the PRIMARY & AUTO INCREMENT Key. So remove id_galeri
I don't think your SQL statement is complete. You should have something like the following:
UPDATE table SET field = '$value' WHERE id = '$id'
you can check out your primary key field auto increment field.
if in your table any data stored then first up all take data backup then remove data and ALTER TABLE table CHANGE your primary key field your primary key field INT(11) NOT NULL AUTO_INCREMENT;

Resources