DELETE USING in gorm? - go-gorm

The title pretty much said it all.
In Postgre we have DELETE FROM ... USING ... WHERE ...
In gorm, I can not see that option any where. I try to avoid sub select as much as possible

Here i have used Postgresql and used db.Raw() function to run DELETE FROM ... USING ... WHERE ... command
I have created 2 table of customer and owner in postgresql inserted data manually using psql cli
Before running any Golang program
customer table :
owner table :
package main
import (
"log"
"gorm.io/driver/postgres"
"gorm.io/gorm"
)
type customer struct {
Id int `gorm:"id"`
First_name string `gorm:"first_name"`
Last_name string `gorm:"last_name"`
Email string `gorm:"email"`
Gender string `gorm"gender"`
Ip_address string `gorm:"ip_address"`
}
func main () {
dburl:= "postgres://postgres:password#localhost:5432"
db,err := gorm.Open(postgres.Open(dburl),&gorm.Config{})
if err !=nil {
log.Fatalln("error connnection")
}
// db.Exec("DELETE customer using owner WHERE customer.first_name = owner.first_name ")
var s customer
db.Raw("DELETE FROM customer using owner WHERE customer.first_name = owner.first_name ").Scan(&s)
}
After running this Golang code first_name field is deleted from customer table :

Related

Golang Route for insert - PrepareContext error

I want to create route /bid/:id/:time/:offer for inserting row in database. But my struct consists of two more rows:userid and time_set. Userid is id of user that made the bid and time_set is timestamp in the moment of inserting or now(). This is my postgres repository in golang.
func (m *postgresBidRepository) CreateNewBid(ctx context.Context, id int64, time int64, offer int64) (err error) {
query := `INSERT bid SET id=? , time=? ,offer=? ,setAt=? ,userId=?`
stmt, err := m.Conn.PrepareContext(ctx, //WHAT HERE)
I want to take id,time and offer from header and current timestamp and userId and insert it. What should I write inside PrepareContext?? when I write id, time,offer... it returs error:
cannot use id (variable of type int64) as string value in argument to m.Conn.PrepareContext
PrepareContext() except two arguments ctx and query string. You should pass the query string like this :
stmt, err := m.Conn.PrepareContext(ctx,query)
Since, you are using interpolation mode. In this mode, driver actually does three actions :
Prepare a statement.
Execute the prepared statement using given args.
Close the prepared statement.
That is exactly the slogan of prepared statement Prepare Once, Execute Many.
After preparing the statement you should execute it like this :
res, err := stmt.ExecContext(ctx, id, time, offer, setAt, userId)
Make sure you should pass the values for all the placeholder(?) query string else it will through an error.
In your case either you can initialize the value inside CreateNewBid() or make a external function and call it inside CreateNewBid() as per the requirement.

How to run a string containing a static SQL query in PostgreSQL?

I have a function which generates a static SQL query and returns it as a string. What I need to do is to run the returned string as if I was typing it directly in psql. Here is a very simplified test case (the true mechanism is far more complicated but the following test case at least shows the idea)
drop table if exists person;
create table person(
first_name varchar(30),
last_name varchar(50),
email varchar(100)
);
insert into person(first_name, last_name, email) values
('fname01', 'lname01', 'fname01.lname01#hotmail.com'),
('fname02', 'lname02', 'fname02.lname02#hotmail.com'),
('fname03', 'lname03', 'fname03.lname03#hotmail.com'),
('fname04', 'lname04', 'fname04.lname04#hotmail.com'),
('fname05', 'lname05', 'fname05.lname05#hotmail.com');
--
--
drop function if exists sql_gen;
create function sql_gen() returns text as
$fun$
begin
return 'select * from person';
end;
$fun$
language plpgsql;
--
--
Now if I run the following:
select * from sql_gen();
sql_gen
----------------------
select * from person
(1 ligne)
This gives me the sql query. But what I want to do is to run the query from
the returned string as if I was writing manually select * from person in psql
and hitting Enter in order to obtain the result of the query.
I've checked PREPARE, EXECUTE on the online documentation but so far I've not been able to achieve this. Could you kindly make some clarification?
And answer specific for psql is to change your semicolon to \gexec.
select * from sql_gen() \gexec

Delete statement with JDBC have no effect

I am using oracle 19c on windows platform.
username and password is hr/hr
try{
//step1 load the driver class
Class.forName("oracle.jdbc.driver.OracleDriver");
//step2 create the connection object
Connection con=DriverManager.getConnection(
"jdbc:oracle:thin:#localhost:1521/orclpdb","hr","hr");
//step3 create the statement object
Statement stmt=con.createStatement();
int deletedRows = stmt.executeUpdate("DELETE FROM my_employee WHERE LAST_NAME LIKE '%man%'");
if(deletedRows>0){
System.out.println("Deleted Specific Row in the table successfully...");
}else{
System.out.println("Not exist specific row that you select for delete");
}
con.close();
}catch(Exception e){ System.out.println(e);}
Not working. There is no error showing, no syntax error.
But output here is:
Not exist specific row that you select for delete
After using select * from my_employee:
Here is the table row (with no effect of delete statement):
EMPLOYEE_ID FIRST_NAME LAST_NAME DEPARTMENT_ID SALARY
----------- -------------------- ------------------------- ------------- ----------
1 asaamansad asdamansda 12 21312
But same SQL command:
delete from my_employee where LAST_NAME LIKE '%man%';
This one works on command prompt or sql developer.
The above row got deleted when the same sql command used on command prompt.
Please solve this problem.

Using multi-column SETOF result from a PL/pgSQL function in via jdbc

When executing a PL/pgSQL function returning a result of a query, Postgresql jdbc driver seems to return only a single column ResultSet. I cannot figure out how to access the members of the "tuple".
For example, if I have a database
CREATE TABLE things (id SERIAL PRIMARY KEY, name VARCHAR);
INSERT INTO things (name) VALUES ('pen'), ('eraser');
-- function to return all rows as a SETOF
CREATE OR REPLACE FUNCTION list_things () RETURNS SETOF things AS $$
BEGIN
RETURN QUERY SELECT id, name FROM things;
END
$$ LANGUAGE PLPGSQL;
and I use the PL/pgSQL function list_things() from Java like this:
static void printThings(Connection c) throws SQLException {
Statement s = c.createStatement();
String sql = "SELECT list_things()";
ResultSet rs = s.getResultSet();
while (rs.next()) {
// is String all I can make of it?
System.out.println(rs.getString(1));
// how can I access the name member of result row?
}
}
The output looks like
(1,pen)
(2,eraser)
How can I access the members of tuples other than by parsing the string?
change
SELECT list_things()
to
SELECT * from list_things()
so it would return rows as they are and not as one tuple with row type

How to check if a table contains any rows when passing the table name as a parameter?

I was trying to write a statement to check if an table contains rows:
SELECT COUNT(*) FROM $1 ;
If figured I would pass in the table name into: $1
I get the following error message:
syntax error at or near "$1"
What is wrong with my statement ?
you can't do it with prepared statement. use function as Kirk suggests. The only difference, maybe you are safer to select first row, like :
t=# create or replace function tempty(tn text) returns boolean as
$$
declare
c int;
begin
execute format('select 1 from %I limit 1',tn) into c;
return NOT coalesce(c,0) > 0;
end;
$$ language plpgsql
;
CREATE FUNCTION
t=# create table empty(i int);
CREATE TABLE
t=# select tempty('empty');
tempty
--------
t
(1 row)
t=# select tempty('pg_class');
tempty
--------
f
(1 row)
docs do not say directly that values you pass to execute prepared statement can't be identifiers, yet everywhere they are mentionned in a way that identifier could not be, eg:
A generic plan assumes that each value supplied to EXECUTE is one of
the column's distinct values and that column values are uniformly
distributed.
($1 is a column value with or without some properties.)
The base driver does only the basic query formatting that's supported on the server level, which doesn't support dynamic table names.
This means the table name needs to be escaped on your side. You can either do this manually, or you can rely on a library that supports it, like the example below that uses pg-promise:
db.one('SELECT count(*) FROM $1:name', table, a => +a.count)
.then(count => {
// count = the integer record count
})
.catch(error => {
// either table doesn't exist, or a connectivity issue
});
Or, by using Named Parameters:
db.one('SELECT count(*) FROM ${table:name}', {table}, a => +a.count)
.then(count => {
// count = the integer record count
})
.catch(error => {
// either table doesn't exist, or a connectivity issue
});
Filter :name tells the formatting engine to escape it as an SQL Name. This filter also has a shorter version ~, if you prefer, i.e. $1~ or ${table~} accordingly.
Also, we are using method one, because that query always expects one-row result back.
You can get this information from the system catalog a lot cheaper and faster than querying the table itself.
CREATE OR REPLACE FUNCTION table_empty(tablename text, tableschema text)
RETURNS BOOLEAN AS $$
BEGIN
RETURN (SELECT CASE WHEN (reltuples::integer > 0)
THEN false
ELSE (SELECT count(*) = 0
FROM quote_ident(tableschema || '.' || tablename) )
END
FROM pg_namespace nc
JOIN pg_class c
ON nc.oid = c.relnamespace
WHERE relname=tablename AND nc.nspname = tableschema);
END;
$$
LANGUAGE plpgsql;
SELECT table_empty('pg_class','pg_catalog');
table_empty
-----------
f
1 row