Preventing duplicate entry in database before inserting value into database - mysql

I am trying to check the database to see if the activity Name that I am entering already exists, if it exists I should get an error if it don't it should go ahead and insert values into database, below is the code I am trying but it isn't working properly btw the prevention of duplicates is already working cause of the UNIQUE KEY i give to activity Name but I also want an alert to let the users know that the activity name already exists.
function insertQueryDB(tx) {
var myDB = window.openDatabase("test", "1.0", "Test DB", 1000000);
tx.executeSql('CREATE TABLE IF NOT EXISTS dataEntryTb (id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, activityName TEXT NOT NULL UNIQUE, location TEXT NOT NULL, time NOT NULL, date NOT NULL, reporter NOT NULL)');
var an = document.forms["myForm"]["activityName"].value;
var l = document.forms["myForm"]["location"].value;
var t = document.forms["myForm"]["time"].value;
var d = document.forms["myForm"]["date"].value;
var r = document.forms["myForm"]["reporter"].value;
if('COUNT activityName FROM dataEntryTb WHERE EXISTS activityName = "'+an+'" '){
navigator.notification.alert("activityName already Exists");
}
var query = 'INSERT INTO dataEntryTb ( activityName, location, time, date, reporter) VALUES ( "'+an+'", "'+l+'", "'+t+'", "'+d+'", "'+r+'")';
tx.executeSql(query,[]);
navigator.notification.alert("Retrieved the following: Activity Name="+an+" and Location="+l);
}

I think all you need to do is establish an unique key on activityName...
alter table dataEntryTb add unique key (activityName);

Related

update only null value columns in table if ID exits in table

I am trying to check for the ID. If it does not exist I want my data to be inserted as a new record in table and if ID exists I want to compare both incoming new record and existing record and only update the values which are null in existing record. I have written the query but I don't know how to check for null in each column:
Here is the query:
insert into ui_table(MDMID,FirstName,Lastname,Mail,Address,City,State,Zip,ProfileStatus,TAID)
select im.MDMID,im.FirstName,im.Lastname,im.Mail,im.Address,im.City,im.State,im.Zip,im.ProfileStatus,im.TAID
from intermediate im on duplicate key update
MDMID = im.MDMID,
FirstName = im.FirstName,
Lastname = im.Lastname,
Mail = im.Mail,
Address = im.Address,
City = im.City,
State = im.State,
Zip = im.Zip,
ProfileStatus = im.ProfileStatus,
TAID = im.TAID;

Parameter index out of range with Multiple Join and Optional input parameter

I have an issue with the multiple Join using Spring JdbcTemplate if I need to make optional the input parameters.
This is the scenario.
The SQL table where i must perform the Join are:
CREATE TABLE users (
id INT NOT NULL AUTO_INCREMENT,
name VARCHAR(15),
password VARCHAR(20),
info VARCHAR(30),
active BOOLEAN,
locked BOOLEAN,
lockout_duration INT DEFAULT 0,
lockout_limit DATETIME,
login_attempts INT DEFAULT 0,
PRIMARY KEY(id)
);
CREATE TABLE profiles (
id INT NOT NULL AUTO_INCREMENT,
name VARCHAR(15),
info VARCHAR(30),
PRIMARY KEY(id)
);
CREATE TABLE profiling(
user_id INT NOT NULL,
profile_id INT NOT NULL,
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
FOREIGN KEY (profile_id) REFERENCES profiles(id) ON DELETE CASCADE,
PRIMARY KEY(user_id,profile_id)
);
Where profiling is the table to associate a user with his profile; the profile must be intended as the identification of what actions are permitted to users.
In one my precedent post, i ask how to make optional the sql parameters and I obtained a perfect response, that works and i have always used since then. So, if i need to make this, is put in the where:
WHERE (is null or variabile_name = ?)
And, using jdbctemplate, i write:
jdbcTemplate.query(SQL, new Object[]{variabile_name, variabile_name}, mapper_name);
where, of course, SQL is the String object where i make the Query.
So, i make this also in this case, but i got the error:
java.lang.IllegalStateException: Failed to execute CommandLineRunner
Caused by: java.sql.SQLException: Parameter index out of range (3 > number of parameters, which is 2).
I report the full method here:
/**
* This metod return the join between users and profiles
* made using the profiling table
*
* #param userID the user id code
* #param profilesID the profile id code
* #return the join list
*/
public List<Profiling> joinWithUsersandProfiles(Integer userID, Integer profileID)
{
//This is the mapper for Profiling
RowMapper<Profiling> profilingMapper = new RowMapper<Profiling>()
{
//This method must be implemented when we use a row mapper
public Profiling mapRow(ResultSet rs, int rowNum) throws SQLException
{
Profiling profiling = new Profiling();
profiling.setUser_id(rs.getInt("profiling.user_id"));
profiling.setProfile_id(rs.getInt("profiling.profile_id"));
//mapping users variabiles
profiling.setUsersId(rs.getInt("users.id"));
profiling.setUsersActive(rs.getBoolean("users.active"));
profiling.setUsersInfo(rs.getString("users.info"));
profiling.setUsersLocked(rs.getBoolean("users.locked"));
profiling.setUsersLockoutDuration(rs.getInt("users.lockout_duration"));
profiling.setUsersLockoutLimit(rs.getTime("users.lockout_limit"));
profiling.setUsersLoginAttempts(rs.getInt("users.login_attempts"));
profiling.setUsersName(rs.getString("users.name"));
profiling.setUsersPassword(rs.getString("users.password"));
//mapping profiles variabiles
profiling.setProfilesId(rs.getInt("profiles.id"));
profiling.setProfilesInfo(rs.getString("profiles.info"));
profiling.setProfilesName(rs.getString("profiles.name"));
return profiling;
}
};
/**
* This is the string that contain the query to obtain the data from profiling table.
* Please note that the notation "? is null or x = ?" means that the x variabile is optional;
* it can be asked as no making the query.
* If we give alla input equals null, it means that we must perform a SQl Select * From table.
*/
String SQL = "SELECT * FROM profiling JOIN users ON profiling.user_id = users.id JOIN profiles ON profiling.profile_id = profiles.id WHERE (is null or profiling.user_id = ?) AND (is null or profiling.profile_id = ?)";
/**
* The list containing the results is obtained using the method query on jdcbtemplate, giving in in input to it the query string, the array of object
* containing the input variabile of the method and the rowmapper implemented.
*/
List<Profiling> theProfilings = jdbcTemplate.query(SQL, new Object[]{userID, userID, profileID, profileID}, profilingMapper);
return theProfilings;
}
I know that the problem is made by the optional variabile. Why? if i try to remove the optional code and pass from:
(is null or variabile_name = ?)
to
variabile_name = ?
The code work perfectly.
So, what's my error here?
Edit: solved myself. I forgot the ? BEFORE the "is null" code. So, passing to:
(? is null or variabile_name = ?)
The code works.

What's the best way to structure a log table which shows differently in each view?

I need to design the structure of a table that is going to store a log of events/actions for a project management website.
The problem is, these logs will be spelled differently depending on what the user is viewing
Example:
On the overview, an action could say "John F. deleted the item #2881"
On the single-item page, it would say "John F. deleted this item"
If the current user IS John F. it would spell "You deleted this item"
I'm not sure if I should store each different possibility in the table, this doesn't sound like the optimal approach.
For any kind of logs you can use the following table structure
CREATE TABLE logs (
id bigint NOT NULL AUTO_INCREMENT,
auto_id bigint NOT NULL DEFAULT '0',
table_name varchar(100) NOT NULL,
updated_at datetime DEFAULT NULL,
updated_by bigint NOT NULL DEFAULT '0',
updated_by_name varchar(100) DEFAULT NULL,
PRIMARY KEY (id)
) ENGINE=InnoDB AUTO_INCREMENT=3870 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
And then create another table to record what columns were updated exactly.
CREATE TABLE logs_entries (
id bigint NOT NULL AUTO_INCREMENT,
log_id bigint NOT NULL DEFAULT '0',
field_name varchar(100) NOT NULL,
old_value text,
new_value text,
PRIMARY KEY (id),
KEY log_id (log_id),
CONSTRAINT logs_entries_ibfk_1 FOREIGN KEY (log_id) REFERENCES logs (id) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=7212 DEFAULT CHARSET=utf8mb3
Now your table data look like this
Now Create a Database-View to fetch data easily in simple query
DELIMITER $$
ALTER ALGORITHM=UNDEFINED SQL SECURITY DEFINER VIEW view_logs_entries AS
SELECT
le.id AS id,
le.log_id AS log_id,
le.field_name AS field_name,
le.old_value AS old_value,
le.new_value AS new_value,
l.auto_id AS auto_id,
l.table_name AS table_name,
l.updated_at AS updated_at,
l.updated_by AS updated_by,
l.updated_by_name AS updated_by_name
FROM (logs_entries le
LEFT JOIN logs l
ON ((le.log_id = l.id)))$$
DELIMITER ;
After creating database-view your data will look like this, so now you can easily query any logs of your project
You must have noticed that I have added updated_by and updated_by_name columns in logs table, Now there are two ways to fill this updated_by_name column
You can write a query on every log entry to fetch user name and store it(not recommended)
You can make a database-trigger to fill this column (Recommended)
You can create database trigger like this, it will automatically insert user name whenever logs entry added in database.
DELIMITER $$
USE YOUR_DATABASE_NAME$$
CREATE
TRIGGER logs_before_insert BEFORE INSERT ON logs
FOR EACH ROW BEGIN
SET new.updated_by_name= (SELECT fullname FROM users WHERE user_id = new.updated_by);
END;
$$
DELIMITER ;
After doing all this, you can insert entries in logs table whenever you do changes in any database table. In my case I have PHP-CodeIgniter project, and I did it like this in my Model file, here I am updating patient table of my database
public function update($id,$data)
{
// Log this activity
$auto_id = $id;
$table_name = 'patients';
$updated_by = #$data['updated_by'];
$new_record = $data;
$old_record = $this->db->where('id',$auto_id)->get($table_name)->row();
$data['updated_at'] = date('Y-m-d H:i:s');
$this->db->where('id', $id);
$return = $this->db->update($table_name,$data);
//my_var_dump($this->db->last_query());
if($updated_by)
{
$this->log_model->set_log($auto_id,$table_name,$updated_by,$new_record,$old_record);
}
return $return;
}
set_log function code checks which fields are actually changed
public function set_log($auto_id,$table_name,$updated_by,$new_record,$old_record)
{
$entries = [];
foreach ($new_record as $key => $value)
{
if($old_record->$key != $new_record[$key])
{
$entries[$key]['old_value'] = $old_record->$key;
$entries[$key]['new_value'] = $new_record[$key];
}
}
if(count($entries))
{
$data['auto_id'] = $auto_id;
$data['table_name'] = $table_name;
$data['updated_by'] = $updated_by;
$this->insert($data,$entries);
}
}
and insert log function look like this
public function insert($data,$entries)
{
$data['updated_at'] = date('Y-m-d H:i:s');
if($this->db->insert('logs', $data))
{
$id = $this->db->insert_id();
foreach ($entries as $key => $value)
{
$entry['log_id'] = $id;
$entry['field_name'] = $key;
$entry['old_value'] = $value['old_value'];
$entry['new_value'] = $value['new_value'];
$this->db->insert('logs_entries',$entry);
}
return $id;
}
return false;
}
You need to separate data from display. In your log, store the complete information (user xxx deleted item 2881). In your log viewer, you have the luxury of substituting as needed to make it more readable.

Chromium Web Browser: "There has been an error: could not prepare statement (1 table items has no column named due_date)"

I use websql for offline storage. Following addItem function works for other browsers, except Chromium:
itemset.webdb.createTable = function() {
var db = itemset.webdb.db;
db.transaction(function(tx) {
tx.executeSql("CREATE TABLE IF NOT EXISTS items(ID INTEGER PRIMARY KEY ASC,
item_name TEXT, desp TEXT, due_date DATE)", []);
});
}
itemset.webdb.addItem = function(item_name, desp, due_date) {
var db = itemset.webdb.db;
db.transaction(function(tx){
//var added_on = new Date();
tx.executeSql("INSERT INTO items(item_name, desp, due_date) VALUES (?,?,?)",
[item_name,desp,due_date],
itemset.webdb.onSuccess,
itemset.webdb.onError);
});
}
Chromium gives error: "There has been an error: could not prepare statement (1 table items has no column named due_date)". Why it does not work?
just have to add the new field in to table, for example next code :
db.transaction(function(txt))
{
txt.executeSql("ALTER TABLE items ADD item_name TEXT, desp TEXT, due_date DATE");
}
Create new table name or Drop and create the table.

SQL Server 2008 Merge Soft Delete Error

I'm trying to perform a soft delete on a row in my target table using the SQL server 2008 MERGE command.
I think this should fall under the "when not matched by source" section, since the source is missing the row and the target still has it. All I want to do is set the IsActive bit to false, but I'm getting an error.
"Attempting to set a non-NULL-able column's value to NULL."
What am I missing?
The Users table is:
[ID] [nvarchar](50) NOT NULL,
[FirstName] [nvarchar](200) NULL,
[LastName] [nvarchar](200) NULL,
[EmailAddress] [nvarchar](200) NULL,
[IsActive] [bit] NOT NULL
The Merge statement is:
merge into Users
using TempUserTable lu
on Users.ID = TempUserTable.ID
when matched then
update set
ID = lu.ID,
FirstName = lu.FirstName,
LastName = lu.LastName,
EMailAddress = lu.EmailAddress,
IsActive = lu.Status
when not matched then
insert (ID, FirstName, LastName, EmailAddress, IsActive)
values (lu.ID, lu.FirstName, lu.LastName, lu.EmailAddress, lu.Status)
when not matched by source then
update set IsActive = 0;
You can get this to work exactly as you want but for me I needed to add a condition in the NOT MATCHED line.
So try something like...
WHEN NOT MATCHED BY SOURCE
AND TARGET.[IsActive] = 1
AND TARGET.[DeletedOn] IS NULL
THEN UPDATE
SET
TARGET.[IsActive] = 0,
TARGET.[DeletedOn] = SYSDATETIMEOFFSET()
It appears that your temp table TempUserTable either has a NULL in the IsActive column or the ID column.