I have a table with the following fields :
PersonnelTable Table fields:
* FirstName
* LastName
* Address
* IdNumber
* UserName
* Password
* Status
In that table I allow duplicate records .
I want to remove one occurrence from that table where :
String sqlStatement = "DELETE FROM `PersonnelTable` WHERE `Password` = ? AND `UserName` = ? ";
m_prepared.setString(1, _password); // set the password
m_prepared.setString(2, _username); // set the user-name
int rowsAffected = m_prepared.executeUpdate();
But that query would remove all the records where Password = ? and UserName = ?
How can I remove only one record using that query ?
Thanks
The LIMIT clause can be used in UPDATE or DELETE statements too:
"DELETE FROM `PersonnelTable` WHERE `Password` = ? AND `UserName` = ? LIMIT 1"
How can I remove only one record using that query ?
You can use the "LIMIT 1" clause of mySQL's DELETE statement.
But if you want to remove all but last rows, you need to do this:
BEGIN TRANSACTION;
SELECT COUNT(*) FROM `PersonnelTable` WHERE `Password` = ? AND `UserName` = ? FOR UPDATE;
DELETE FROM `PersonnelTable` WHERE `Password` = ? AND `UserName` = ? LIMIT ?; # (last fetched count - 1)
COMMIT;
Related
I am created a prepared select query and it appears the query is not picking up the DESC or I have the bind_param structured wrong. I am trying to get the last id of the user_id's image to display. The user's image displays, but it is the first id image they have. I tried doing ASC and it was the same thing.
Am I doing this right?
$sql = "
SELECT *
FROM profile_img
WHERE user_id = ?
ORDER BY ? DESC LIMIT 1
";
if ($stmt = $con->prepare($sql)) {
$stmt->bind_param("ss", $user_id, `id`);
$stmt->execute();
if (!$stmt->errno) {
// Handle error here
}
$stmt->bind_result($id, $user_id, $profilePic);
$pics = array();
while ($stmt->fetch()) {
$pics[] = $profilePic;
}
echo '<img id="home-profile-pic" src=" '.$profilePic.'">';
}
I don't think you can :
Use placeholders in an order by clause
Bind column names : you can only bind values -- or variables, and
have their value injected in the prepared statement.
You can use number instead of field name in the 'order by' clause
Why you have put ? after "order by" statement?
Your order by should reference to either id of your "profile_img" table or any timestamp field in that table...
e.g. $sql = "
SELECT *
FROM profile_img
WHERE user_id = ?
ORDER BY id DESC LIMIT 1
";
here replace id (i am assuming this name) with the primary key field name of profile_image table
or
$sql = "
SELECT *
FROM profile_img
WHERE user_id = ?
ORDER BY created_on DESC LIMIT 1
";
here created_on (which i have also assumed) can be replaced by any timestamp field if you any in profile_img table
Right now I have created a sequence and a trigger to auto increment the ID value like this:
CREATE OR REPLACE TRIGGER "RTH"."TBL_USER_TRIGGER"
BEFORE INSERT ON TBL_USER
FOR EACH ROW
BEGIN
SELECT TBL_USER_SEQ.nextval
INTO :new.USR_ID
FROM dual;
END;
ALTER TRIGGER "RTH"."TBL_USER_TRIGGER" ENABLE;
Let say I have three rows:
User ID FIRSTNAME LASTNAME
====================================
1 John smith
2 James smith
3 Pat smith
When I delete the first row(1) I want the ID values to auto correct itself to correct numbers so that second row ID values becomes 1 and third row ID values becomes 2
Is it possible in oracle? or do I have do it through code as I am using Java to insert records into table when user submits a form.
Java DAO class:
public class RegistrationDAO {
public void insert(User user) {
try {
Connection con = DBConnection.getConnection();
String query = "insert into TBL_USER(USR_FIRST_NAME,USR_LST_NAME,USR_PRIMARY_EMAIL,USR_PASSWORD) values(?,?,?,?)";
PreparedStatement pst = con.prepareStatement(query);
pst.setString(1, user.getFirstName());
pst.setString(2, user.getLastName());
pst.setString(3, user.getEmail());
pst.setString(4, user.getPassword());
pst.executeUpdate();
} catch (Exception e) {
System.out.println("####Record insertion error in Registration DAO####");
System.out.println(e);
}
}
}
The simple answer is: "No, you don't want to do that." The purpose of an id is to uniquely identify each row. A sequential id also has the feature that it provides insertion order. It is not intended to change over time. Row 1 is Row 1 is Row 1.
If you want ordering, then declare the id to be the primary key and use a query such as this:
select t.*, row_number() over (order by usr_id) as seqnum
from t;
Ideally, you should not be changing USER ID values. But still if there is requirement. Then below are the steps.
Create a procedure to reset the sequence TBL_USER_SEQ. This is needed as you are resetting the USER ID values. So after resetting, whenever you insert new record, Sequence should start with proper value ( i.e. MAX USER_ID value of the table). So that there will be no gap in USER_ID
Write Delete Trigger on table which will adjust USER_ID values.
Procedure to reset sequence
CREATE OR REPLACE PROCEDURE reset_sequence_p (p_seq IN VARCHAR2, p_new_seq NUMBER)
AS
l_value NUMBER;
BEGIN
-- Select the next value of the sequence
EXECUTE IMMEDIATE 'SELECT ' || p_seq || '.NEXTVAL FROM DUAL' INTO l_value;
-- Alter the sequnce to increment by the difference
EXECUTE IMMEDIATE 'ALTER SEQUENCE ' || p_seq || ' INCREMENT BY ' || ( p_new_seq - l_value ) ;
-- Increment to next value after diference
EXECUTE IMMEDIATE 'SELECT ' || p_seq || '.NEXTVAL FROM DUAL' INTO l_value;
-- Set the increment back to 1
EXECUTE IMMEDIATE 'ALTER SEQUENCE ' || p_seq || ' INCREMENT BY ' || 1 ;
END reset_sequence_p;
Delete Trigger
CREATE OR REPLACE TRIGGER "RTH"."TBL_USER_TRIG_DEL"
BEFORE DELETE
ON TBL_USER
FOR EACH ROW
DECLARE
v_new_user_id_seq NUMBER;
PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
-- Update USER_ID value for all remaining records greater than USER_ID that got deleted.
UPDATE TBL_USER
SET USER_ID = USER_ID - 1
WHERE USER_ID > :old.USER_ID;
-- Retrieve max USER_ID available in table.
SELECT MAX (user_id) INTO v_new_user_id_seq FROM TBL_USER;
-- Call procedure to reset sequence
reset_sequence_p ('TBL_USER_SEQ', v_new_user_id_seq);
COMMIT;
END;
NOTE : Make sure that Primary key on table is disabled before execution of Delete statement.
I hope this helps.
I have updatable view on PostgreSQL server.
Update query works fine when I execute it from pgAnmin3 console, but when I try to update this view with ResultSet.updateRow() method, I get the following error:
org.postgresql.util.PSQLException: No primary key found for table
I guess I can't specify primary key for view.
Can I specify key columns for ResultSet.updateRow() method in my client application? Or can I specify a WHERE clause for ResultSet.updateRow() method?
Here are my tables
CREATE TABLE fin.t_year
(
id serial NOT NULL,
date_begin date NOT NULL,
date_end date NOT NULL,
year_name character varying(128),
CONSTRAINT "PK_year" PRIMARY KEY (id)
)
WITH (
OIDS=FALSE
);
CREATE TABLE fin.t_period
(
id serial NOT NULL,
id_year integer NOT NULL,
per_begin date NOT NULL,
per_end date NOT NULL,
per_name character varying(256),
CONSTRAINT "PK_period" PRIMARY KEY (id),
CONSTRAINT "FK_period_year" FOREIGN KEY (id_year)
REFERENCES fin.t_year (id) MATCH SIMPLE
ON UPDATE NO ACTION ON DELETE NO ACTION
)
WITH (
OIDS=FALSE
);
CREATE VIEW fin.vi_period AS
SELECT per.id,
per.per_begin AS "Begin",
per.per_end AS "End",
per.per_name AS "Name",
y.year_name AS "Year"
FROM fin.t_period per
JOIN fin.t_year y ON y.id = per.id_year;
CREATE OR REPLACE FUNCTION fin.tgfn_vi_period_update()
RETURNS trigger AS
$BODY$
DECLARE
id_row INTEGER;
id_curr INTEGER;
result RECORD;
BEGIN
id_curr = NEW.id;
-- Replace text identifier with integer primary key
IF NEW."Year" IS NOT NULL THEN
SELECT id INTO id_row
FROM fin.t_year
WHERE year_name = NEW."Year";
UPDATE fin.t_period SET id_year = id_row
WHERE id = id_curr;
END IF;
IF NEW."Begin" IS NOT NULL THEN
UPDATE fin.t_period SET per_begin = NEW."Begin"
WHERE id = id_curr;
END IF;
IF NEW."End" IS NOT NULL THEN
UPDATE fin.t_period SET per_end = NEW."End"
WHERE id = id_curr;
END IF;
IF NEW."Name" IS NOT NULL THEN
UPDATE fin.t_period SET per_name = NEW."Name"
WHERE id = id_curr;
END IF;
SELECT * INTO result FROM fin.vi_period WHERE id = id_curr;
RETURN result;
END;
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100;
This insert statement works fine
UPDATE fin.vi_period SET "Year" = 'new_year_name' WHERE id = 10;
But the problem with this java code
statement = conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE);
ResultSet rs = statement.ExecuteQuery("SELECT * FROM fin.vi_period;");
rs.absolute(pos + 1);
rs.updateString("new_year_name");
rs.updateRow();
The problem is that you are querying a view, and that view doesn't have a primary key (I am not sure if that is even possible with PostgreSQL, but most database don't support that). The JDBC driver requires a primary key to be able to make the result set updatable.
In other words: you cannot update this view through the result set. You either need to use an explicit UPDATE statement, or do this directly on the underlying table, not through the view.
Suppose I have the query:
SELECT * FROM CUSTOMERS WHERE CUSTOMER_ID = ?
With PreparedStatement, I can bind the variable:
pstmt.setString(1, custID);
However, I cannot obtain the correct results with the following binding:
pstmt.setString(1, null);
As this results in:
SELECT * FROM CUSTOMERS WHERE CUSTOMER_ID = NULL
which does not give any result. The correct query should be:
SELECT * FROM CUSTOMERS WHERE CUSTOMER_ID IS NULL
The usual solutions are:
Solution 1
Dynamically generate query:
String sql = "SELECT * FROM CUSTOMERS WHERE CUSTOMER_ID "
+ (custID==null ? "IS NULL" : "= ?");
if (custID!=null)
pstmt.setString(1, custID);
Solution 2
Use NVL to convert null value to a gibberish value:
SELECT * FROM CUSTOMERS WHERE NVL(CUSTOMER_ID, 'GIBBERISH') = NVL(?, 'GIBBERISH');
But you need to be 100% sure that the value 'GIBBERISH' will never be stored.
Question
Is there a way to use a static query and avoid depending on gibberish value conversions? I am looking for something like:
SELECT * FROM CUSTOMERS
WHERE /** IF ? IS NULL THEN CUSTOMER_ID IS NULL ELSE CUSTOMER_ID = ? **/
I think I may have a working solution:
SELECT * FROM CUSTOMERS
WHERE ((? IS NULL AND CUSTOMER_ID IS NULL) OR CUSTOMER_ID = ?)
pstmt.setString(1, custID);
pstmt.setString(2, custID);
Will the above work reliably? Is there a better way (possibly one that requires setting the parameter only once)? Or is there no way to do this reliably at all?
Your working solution is fine (and similar to what I've used before). If you only want to bind once you can use a CTE or inline view to provide the value to the real query:
WITH CTE AS (
SELECT ? AS REAL_VALUE FROM DUAL
)
SELECT C.* -- but not * really, list all the columns
FROM CTE
JOIN CUSTOMERS C
ON (CTE.REAL_VALUE IS NULL AND C.CUSTOMER_ID IS NULL)
OR C.CUSTOMER_ID = CTE.REAL_VALUE
So there is only one placeholder to bind.
I don't really see a problem with a branch on the Java side though, unless your actual query is much more complicated and would lead to significant duplication.
WHERE
DECODE(CUSTOMER_ID, NULL, 'NULL', CUSTOMER_ID || 'NOT NULL') =
DECODE(?, NULL, 'NULL', CUSTOMER_ID, CUSTOMER_ID || 'NOT NULL')
This works, I believe
SQLFiddle
Note that in order to test it on sqlfiddle I have had to replace the parameter with a value for each case [NULL, 'NULL', 'SMITH']
Dynamically creating the query works on all JDBCs, so you are not bound to platform-specific SQL.
It wouldn't be that hard to read to create an if-branch, would it?
PreparedStatement pst = null; // Avoid initialisation warnings
if (custID == null)
pst = connection.prepareStatement("SELECT * FROM CUSTOMERS WHERE CUSTOMER_ID IS NULL");
else {
pst = connection.prepareStatement("SELECT * FROM CUSTOMERS WHERE CUSTOMER_ID = ?");
pst.setString(1, custID);
}
ResultSet rs = pst.executeQuery();
In PostgreSQL user is a reserved keyword that is used in an internal table, however I also have a separate user table in my own database that I need to use. Whenever I try to execute INSERT or UPDATE statements on the table, it generates the following error: The column name 'id' was not found in this ResultSet.
This is the Java code I am currently using:
PreparedStatement stat1 = conn.prepareStatement("SELECT id FROM user;");
PreparedStatement stat2 = conn.prepareStatement("UPDATE user SET date_created = ? , last_updated = ? , uuid = ? WHERE id = ?;");
ResultSet rs = stat1.executeQuery();
while(rs.next()){
UUID uuid = UUID.randomUUID();
String tempId = uuid.toString();
stat2.setTimestamp(1, curDate);
stat2.setTimestamp(2, curDate);
stat2.setString(3, tempId);
stat2.setLong(4,rs.getLong("id"));
stat2.executeUpdate();
}
So my question is, how could I insert or update the values in my personal user table without interfering with the keyword restriction?
Use this:
prepareStatement("UPDATE \"user\" set date_created = ?")
Or, better yet, rename your user table to something else, like users:
ALTER TABLE "user" RENAME TO users;
Escape the table name like this
select * from "user";