Postgresql insert into name and value using a variable - sql

I have 2 variables
var anycolumn = 'fruit';
var anyvalue = 'apple';
I was able to insert the value using variable 'anyvalue' like...
"INSERT INTO mytable (fruit) VALUES ($1)", [anyvalue], function(err, result){}
Now how do I insert the column name using variable 'anycolumn'?
I'm using node server
"INSERT INTO mytable (anycolumn) VALUES ($1)", [anyvalue], function(err, result){}

"INSERT INTO mytable ("+anycolumn+") VALUES($1)", [anyvalue]...
But make sure you know for certain what anycolumn contains. Don't use something received directly or indirectly from the outside (e.g. an HTTP request, in the form of parameters, body, cookies, headers...) without validating it, otherwise you'll get a terrible SQL injection.
Also note that this probably means your database schema is incorrect, and you should have a table with columns name and value.

The following example is based on pg-promise:
db.none('INSERT INTO mytable($1~) VALUES($2)', [anycolumn, anyvalue])
.then(()=> {
// success;
})
.catch(error=> {
// error;
});
Using the same SQL Names syntax you can inject the table name as well.

Related

SQL expression for not changing the field in UPDATE?

It must be a classic scenario, but I don't see any question for it...
I receive a lot of arguments in HTTP request for updating a row in the database.
Some other parameters are not set.
I am using some C++ framework for the SQL queries.
And I have a query like:
auto update(R"__(
UPDATE
table
SET
field1 = ?,
field2 = ?
WHERE
id = ?
)__");
exec_update(update, {field1.value_or(<?>), field2.value_or(<?>), id})
Because there can be around 30 fields to update, I don't want to create the query dynamically, but I would rather use some keyword to tell the Postgresql not to change the fields that I don't have new value for, how to achieve that?
Simply, what to put instead of the <?>?
I only found a similar question: How do I update selective fields in SQL (leaving some unchanged)?, which is a special case for this, I want to be able to set even NULL or whatever, I just want to not update some fields from the query without changing the query, I want to just have the values dynamic, not the query.
EDIT: I couldn't find anything better than having the dynamic query like:
auto update(fmt::format(
R"__(
UPDATE
table
SET
field1 = {},
field2 = {},
WHERE
id = {}
)__",
object.get_field1().has_value() ? fmt::format("'{}'", object.get_field1().value())
: "field1",
object.get_field2().has_value() ? fmt::format("'{}'", object.get_field2().value())
: "field2",
id));
, but I am not much satisfied with that.

Parameterization of an array of enums?

I have a table where one of the fields is an array of enums. For example let say this is what it looks like:
CREATE TYPE foobar AS ENUM (
'FOO',
'BAR'
);
CREATE TABLE my_table (
id SERIAL PRIMARY KEY,
foobarray foobar[] DEFAULT ARRAY['FOO']::foobar[]
);
When I try to use node-postgres to insert/update a row it is not clear how to parameterize the array and get it type cast to an array of enums.
When I try:
const foobarray = ["BAR"];
await pool.query("UPDATE my_table SET foobarray=$2::foobar[] WHERE id=$1", [id, foobarray]);
I get:
error: invalid input value for enum foobarray: "{"
Any ideas how to get this to work?
I figured out my issue...
I was actually pulling the value, before updating it, as follows:
SELECT foobarray FROM my_table WHERE id=$1;
This resulted in the following array being in the result:
["{", "}", "FOO"]
I didn't realize this and was trying to modify the array from the result before updating which resulted in "{" and "}" which are obviously not valid ENUM values being passed through.
I was able to solve this issue by keeping my original UPDATE query the same but modifying the SELECT query to:
SELECT foobarray::text[] FROM my_table WHERE id=$1;
This results in the following array being in the result:
["FOO"]
Tweaking it and updating now causes no problems.

DB2 Get column with variable column name

This is an off-shoot of another question I asked, with me trying to solve it myself.
I've figured out how to get the column names for the table I'm in (by querying SYSCAT.COLUMNS). I now need to someone table the value from that, and get the column with that name off of the cursor (basically, a variable column name).
For illustration, in something like JavaScript, I'd just do something like this:
const c = { COLNAME: 'myCol' };
const n = { myCol: '5' };
n[c.COLNAME]
In my cause, c is the cursor with the columns (with COLNAME the name of the column) and n is the row that has a column named the value of c.COLNAME.
If it matters, I'm doing this inside the body of a trigger.
You have to build a dynamic SQL statement...
then PREPARE and EXECUTE or EXECUTE IMMEDIATELY that statement...
As commented in your other post, this is a bad idea to do in a trigger..

Retrieve id of record just inserted into a Java DB (Derby) database

I am connecting to a Java DB database with JDBC and want to retrieve the id (which is on auto increment) of the last record inserted.
I see this is a common question, but I see solutions using for example MS SQL Server, what is the equivalent for Java DB?
No need to use a DBMS specific SQL for that.
That's what getGeneratedKeys() is for.
When preparing your statement you pass the name(s) of the auto-generated columns which you can then retrieve using getGeneratedKeys()
PreparedStatement pstmt = connection.prepareStatement(
"insert into some_table (col1, col2, ..) values (....)",
new String[] { "ID_COLUMN"} );
pstmt.executeUpdate();
ResultSet rs = pstmt.getGeneratedKeys(); // will return the ID in ID_COLUMN
Note that column names are case sensitive in this case (in Derby and many other DBMS).
new String[] { "ID_COLUMN"} is something different than new String[] { "id_column"}
Alternatively you can also use:
connection.prepareStatement("INSERT ...", PreparedStatement.RETURN_GENERATED_KEYS);
You may be able to get what you're looking for using the IDENTITY_VAL_LOCAL function. (Derby Reference)
This function is supposed to return "the most recently assigned value of an identity column for a connection, where the assignment occurred as a result of a single row INSERT statement using a VALUES clause."
It's worth noting that this function will return DECIMAL(31,0), regardless of the actual data type of the corresponding identity column.
Also, this only works for single row inserts that contain a VALUES clause.
For those who have issues getting the generated autoincrement id like I used to for Java Derby, my answer can be of help.
stmt.executeUpdate("INSERT INTO xx(Name) VALUES ('Joe')", Statement.RETURN_GENERATED_KEYS);
ResultSet rs = stmt.getGeneratedKeys();
if (rs.next()) {
int autoKey = rs.getInt(1); //this is the auto-generated key for your use
}
Answer copied from here

Select the last row in a SQL table

Is it possible to return the last row of a table in MS SQL Server.
I am using an auto increment field for the ID and i want to get the last one just added to join it with something else. Any idea?
Here's the code:
const string QUERY = #"INSERT INTO Questions (ID, Question, Answer, CategoryID, Permission) "
+ #"VALUES (#ID, #Question, #Answer, #CategoryID, #Permission) ";
using (var cmd = new SqlCommand(QUERY, conn))
{
cmd.Parameters.AddWithValue("#Question", question);
cmd.Parameters.AddWithValue("#Answer", answer);
cmd.Parameters.AddWithValue("#CategoryID", lastEdited);
cmd.Parameters.AddWithValue("#Permission", categoryID);
cmd.ExecuteNonQuery();
}
Not safe - could have multiple inserts going on at the same time and the last row you'd get might not be yours. You're better off using SCOPE_IDENTITY() to get the last key assigned for your transaction.
using an auto increment field ... and i want to get the last one just added to join it with something else.
The key here is "just added". If you have a bunch of different users hit the db at the same time, I don't think you want user A to retrieve the record created by user B. That means you probably want to use the scope_identity() function to get that id rather than running a query on the table again right away.
Depending on the context you might also need ##identity (would include triggers) or ident_current('questions') (limited to a specific table, but not the specific scope). But scope_identity() is almost always the right one to use.
Here's an example:
DECLARE #NewOrderID int
INSERT INTO TABLE [Orders] (CustomerID) VALUES (1234)
SELECT #NewOrderID=scope_identity()
INSERT INTO TABLE [OrderLines] (OrderID, ProductID, Quantity)
SELECT #NewOrderID, ProductID, Quantity
FROM [ShoppingCart]
WHERE CustomerID=1234 AND SessionKey=4321
Based on the code you posted, you can do something like this:
// don't list the ID column: it should be an identity column that sql server will handle for you
const string QUERY = "INSERT INTO Questions (Question, Answer, CategoryID, Permission) "
+ "VALUES (#Question, #Answer, #CategoryID, #Permission);"
+ "SELECT scope_identity();";
int NewQuestionID;
using (var cmd = new SqlCommand(QUERY, conn))
{
cmd.Parameters.AddWithValue("#Question", question);
cmd.Parameters.AddWithValue("#Answer", answer);
cmd.Parameters.AddWithValue("#CategoryID", lastEdited);
cmd.Parameters.AddWithValue("#Permission", categoryID);
NewQuestionID = (int)cmd.ExecuteScalar();
}
See my answer to another question here:
get new SQL record ID
The problem now is that you'll likely want subsequent sql statements to be in the same transaction. You could do this with client code, but I find keeping it all on the server to be cleaner. You could do that by building a very long sql string, but I tend to prefer a stored procedure at this point.
I'm also not a fan of the .AddWithValue() method — I prefer explicitly defining the parameter types — but we can leave that for another day.
Finally, it's kind of late now, but I want to emphasize that it's really better to try to keep this all on the db. It's okay to run multiple statements in one sql command, and you want to reduce the number of round trips you need to make to the db and the amount of data you need to pass back and forth between the db and your app. It also makes it easier to get the transactions right and keep things atomic where they need to be.
use
scope_identity() returns the last identity value generated in this session and this scope
ident_current() returns the last identity value generated for a particular table in any session and any scope
select ident_current( 'yourTableName' )
will return the last identity created by a different session.
Most of the time you should use scope_identity() right after an insert statement like so.
--insert statement
SET #id = CAST(SCOPE_IDENTITY() AS INT)
MSDN Link - Scope_Identity()
MSDN Link - Ident_Current
select top 1 * from yourtable order by id desc
I'm not sure of your version of SQL Server, but look for the OUTPUT clause of ther INSERT statement. You can capture a set of rows with this clause
Since the questioner is using .NET, here's a modified example of how to do it. (I removed ID from the insert list since it's autoincrement--the original example would fail. I also assume ID is an SQL int, not a bigint.)
const string QUERY = #"INSERT INTO Questions (Question, Answer, CategoryID, Permission) "
+ #"VALUES (#Question, #Answer, #CategoryID, #Permission);"
+ #"SELECT #ID = SCOPE_IDENTITY();";
using (var cmd = new SqlCommand(QUERY, conn))
{
cmd.Parameters.AddWithValue("#Question", question);
cmd.Parameters.AddWithValue("#Answer", answer);
cmd.Parameters.AddWithValue("#CategoryID", lastEdited);
cmd.Parameters.AddWithValue("#Permission", categoryID);
cmd.Parameters.Add("#ID", System.Data.SqlDbType.Int).Direction = ParameterDirection.Output;
cmd.ExecuteNonQuery();
int id = (int)cmd.Parameters["#ID"].Value;
}
EDITED: I also suggest considering LINQ to SQL instead of hand-coding SqlCommand objects--it's much better (faster to code, easier to use) for many common scenarios.
With a simple select you can do something like this:
SELECT *
FROM table_name
WHERE IDColumn=(SELECT max(IDColum) FROM table_name)