violates foreign key constraint - postgresql

I keep receiving this error:
insert or update on table "note" violates foreign key constraint "note_username_fkey"
I have two tables: User and Note. Here are the create table statements:
func setup() *sql.DB {
db = connectDatabase()
//Create queries
userTable := `CREATE TABLE IF NOT EXISTS "User"(
UserID SERIAL unique,
UserName VARCHAR(50) PRIMARY KEY,
FirstName VARCHAR(50),
LastName VARCHAR(50),
Password VARCHAR(40)
);`
noteTable := `CREATE TABLE IF NOT EXISTS Note(
NoteID SERIAL PRIMARY KEY,
UserID INT,
UserName VARCHAR(50),
Title VARCHAR(30),
Contents VARCHAR(1000),
DateCreated DATE,
DateUpdated DATE,
FOREIGN KEY (UserName) REFERENCES "User"(UserName)
);`
}
func createNoteInsertSQL(userID string, userName string, title string, content string, selectSetting string) bool {
var newNote Note
var err error
newNote.UserID, err = strconv.Atoi(userID)
if err != nil {
log.Fatal(err)
}
newNote.UserName = userName
newNote.Title = title
newNote.Contents = content
date := time.Now()
newNote.DateCreated = date
newNote.DateUpdated = date
query := `INSERT INTO Note (UserID, UserName, Title, Contents, DateCreated, DateUpdated) VALUES ($1, $2, $3, $4, $5, $6) RETURNING NoteID;`
stmt, err := db.Prepare(query)
if err != nil {
log.Fatal(err)
return false
}
var noteID int
err = stmt.QueryRow(newNote.UserID, newNote.UserName, newNote.Title, newNote.Contents, newNote.DateCreated, newNote.DateUpdated).Scan(&noteID)
if err != nil {
log.Fatal(err)
return false
}
}
Can anyone please tell me where the wrong ?
Thanks.

Check whether "Username" column value you try to insert in note table is already available in "User" table. Because the insert query is trying to insert value that is not available in "User" table.

Related

fetching data and upsert into database

I want to get data from api and then doing query into specific tables using upsert, for example :
Repository
// get data from api
response, resErr := http.Get("look at json that want to fetch")
if resErr != nil {
fmt.Print(resErr.Error())
return resErr
}
// Read response from the API
defer response.Body.Close()
responseOdoo, err := ioutil.ReadAll(response.Body)
if err != nil {
log.Fatal(err)
}
//unmarshaling data to struct
var responseObject []models.OdooResponse
json.Unmarshal(responseOdoo, &responseObject)
here I want to perform an upsert to an existing table, but I don't know how to combine the data that has been retrieved and then fill it into the query
// get data from table and then upsert into column
qapi := `
insert into services_new
(code, service_id, service_name, service_category_id, service_category, service_type_id, service_type , price, request_type, status, uom_code, created_at , created_by, created_by_name, updated_at, updated_by, updated_by_name)
values
($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,NOW(),$12,$13,NOW(),$12,$13)
on conflict (service_id, service_category_id, service_type_id)
do update set service_name =excluded.service_name, service_category =excluded.service_category, service_type =excluded.service_type, price =excluded.price, request_type =excluded.request_type, status =excluded.status, uom_code =exluded.uom_code, created_at =excluded.created_at, created_by =excluded.created_by, created_by_name =excluded.created_by_name;
`
_, sqlErr := tx.ExecContext(ctx, qapi, request.Code, request.ServiceID, request.ServiceName, request.ServiceCategoryID, request.ServiceCategory, request.ServiceTypeID, request.ServiceType, request.Price, request.RequestType, request.Status, request.UomCode, helper.Fullname, helper.Email)
// checking query upsert services_new
if sqlErr != nil {
tx.Rollback()
log.Println("sql Error on Repository Upsert on ODOO Services", sqlErr)
return sqlErr
}
txErr = tx.Commit()
if txErr != nil {
return txErr
}
return nil
until here, is the flow correct?
JSON That want to fetch
{
"service_id": 1129,
"service_name": "Adobe Illustrator",
"service_category_id": 28,
"service_category_name": "License Software",
"service_type_id": 25,
"service_type_name": "Software",
"create_date": "2020-03-09 03:47:44"
},
struct models
type UpsertFromOdooServices struct {
Code string `json:"code"`
ServiceID uint `json:"service_id"`
ServiceName string `json:"service_name"`
ServiceCategoryID uint `json:"service_category_id"`
ServiceCategory uint `json:"service_category"`
ServiceTypeID uint `json:"service_type_id"`
ServiceType string `json:"service_type"`
Price float64 `json:"price"`
RequestType string `json:"request_type"`
Status string `json:"status"`
UomCode string `json:"uom_code"`
CreatedAt time.Time `json:"created_at"`
CreatedBy string `json:"created_by"`
CreatedByName string `json:"created_by_name"`
UpdatedAt time.Time `json:"updated_at"`
UpdatedBy string `json:"updated_by"`
UpdatedByName string `json:"updated_by_name"`
}
type OdooResponse struct {
ServiceID uint `json:"service_id"`
ServiceName string `json:"service_name"`
ServiceCategoryID uint `json:"service_category_id"`
ServiceCatrgoryName string `json:"service_category_name"`
ServiceTypeID uint `json:"service_type_id"`
ServiceTypeName string `json:"service_type_name"`
Response []UpsertFromOdooServices
}

FMDB insert or replace do multiple entries

I have an sqlite3 table, every time I run my code, it adds multiple entries. How can I change this query to add only one entry?
CREATE TABLE "GroupTable" (
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
"memberId" TEXT NOT NULL,
"adminId" TEXT NOT NULL,
"name" TEXT NOT NULL
);
The method below shows how I am adding data:
func addDatatoList(info: ListModel ) -> Bool
{
sharedInstance.database!.open()
let isInserted = sharedInstance.database!.executeUpdate("INSERT or REPLACE INTO GroupTable(adminId, memberId, name) VALUES (?,?,?)", withArgumentsIn: [ info.adminId,info. memberId,info.name])
sharedInstance.database!.close()
return isInserted
}
You’re not supplying an id value, so INSERT OR REPLACE will never replace. You theoretically could add id parameter, passing NSNull() if the id value is NULL
func addDatatoList(info: ListModel) -> Bool {
guard let db = sharedInstance.database else { return false }
db.open()
defer { db.close() }
let sql = "INSERT or REPLACE INTO GroupTable(id, adminId, memberId, name) VALUES (?, ?, ?, ?)"
let values: [Any] = [info.id ?? NSNull(), info.adminId, info.memberId, info.name]
let isInserted = sharedInstance.database!.executeUpdate(sql, withArgumentsIn: values)
return isInserted
}
That having been said, if you did INSERT, you probably want to retrieve the row’s auto increment id value:
func addDatatoList(info: ListModel) -> Bool {
guard let db = sharedInstance.database else { return false }
db.open()
defer { db.close() }
let sql = "INSERT or REPLACE INTO GroupTable(id, adminId, memberId, name) VALUES (?, ?, ?, ?)"
let values: [Any] = [info.id ?? NSNull(), info.adminId, info.memberId, info.name]
let isInserted = sharedInstance.database!.executeUpdate(sql, withArgumentsIn: values)
if isInserted, info.id == nil {
let id = db.lastInsertRowId
// e.g., if `ListModel` is a reference type and `id` is mutable,
// you might update the value, e.g.
info.id = Int(id)
}
return isInserted
}
But, then again, if you're now programmatically determining whether you inserted or updated, you might as well have two SQL statements, one for INSERT and one for UPDATE.

go pg #42P01 invalid reference to FROM-clause

i am trying to do a left join on query but i have an invalid reference to FROM-Clause
here are the structure of the code
this is the product table
CREATE TABLE products
(
id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
title VARCHAR(255),
productdesc TEXT,
costprice DOUBLE PRECISION,
recommendprice DOUBLE PRECISION,
views BIGINT DEFAULT 0,
enabled BOOLEAN DEFAULT FALSE,
category_id BIGINT REFERENCES categories (id) ON DELETE CASCADE NOT NULL,
)
this is the category table
CREATE TABLE categories
(
id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
pid BIGINT NOT NULL,
title VARCHAR(255),
image VARCHAR(255),
);
this is the type struct
type Product struct {
TableName struct{} `sql:"products"`
ID int64 `json:"id"`
TITLE string `json:"title"`
PRODUCTDESC string `json:"product_desc"`
COSTPRICE float64 `json:"costprice"`
RECOMMENDPRICE float64 `json:"recommendprice"`
VIEWS int64 `json:"views"`
ENABLED bool `json:"enabled"`
CATEGORYNAME string `json:"categoryname"`
}
type Category struct {
tableName struct{} `pg:"categories"`
ID int64 `json:"id"`
Title string `json:"title"`
Image string `json:"image"`
}
this is the actual query to database
func (t *ProductRepo) GetAllProducts() ([]*domain.Product, error) {
var products []*domain.Product
query := t.DB.Model(&products).
ColumnExpr("products.*").
ColumnExpr("c.id AS category_id, c.title AS categoryname").
Join("LEFT JOIN categories AS c ON c.id = products.category_id")
err := query.Select()
if err != nil {
return nil, err
}
return products, nil
}
this is the actual error from postman
{
"error": "ERROR #42P01 invalid reference to FROM-clause entry for table \"products\""
}
any help would be great,
thanks advance
Jason

sqlx scan postgres array into struct

I'm trying to create a basic commenting api in go. I can't seem to figure out how to scan postgresql arrays into an array of structs within a struct. I think I could probably have Thread.Posts type be jsonb but that seems inelegant since I would have to unmarshall it I think.
sql: Scan error on column index 3, name "posts": unsupported Scan,
storing driver.Value type []uint8 into type *[]models.Post
var threadSchema = `
CREATE TABLE IF NOT EXISTS thread (
id SERIAL PRIMARY KEY,
name VARCHAR(100) NOT NULL,
profile_id INTEGER REFERENCES profile (id)
)`
var postSchema = `
CREATE TABLE IF NOT EXISTS post (
id SERIAL PRIMARY KEY,
comment TEXT,
profile_id INTEGER REFERENCES profile (id),
thread_id INTEGER REFERENCES thread (id)
)`
type Post struct {
Id int `db:"id" json:"id"`
Comment string `db:"comment" json:"comment" binding:"required" form:"comment"`
ProfileId int `db:"profile_id" json:"profile_id" binding:"required" form:"profile_id"`
ThreadId int `db:"thread_id" json:"thread_id" binding:"required" form:"thread_id"`
}
type Thread struct {
Id int `db:"id" json:"id"`
Name string `db:"name" json:"name" binding:"required" form:"name"`
ProfileId int `db:"profile_id" json:"profile_id" binding:"required" form:"profile_id"`
Posts []Post `db:"posts" json:"posts" form:"posts"`
}
func GetThreads(db *sqlx.DB, c *gin.Context) {
threads := []Thread{}
err := db.Select(&threads, `
SELECT thread.id,thread.name,thread.profile_id,array_agg(post.id) AS posts
FROM thread
INNER JOIN post ON thread.id = post.thread_id
GROUP BY thread.id;
`)
if err != nil {
log.Fatal(err)
}
c.JSON(http.StatusOK, gin.H{"data": threads})
}
You could define your type:
type Posts []Post
// Scan implements the sql.Scanner interface.
func (a *Posts) Scan(src interface{}) error {
// ...
}
// Value implements the driver.Valuer interface.
func (a Posts) Value() (driver.Value, error) {
// ...
}
For more information on the implementation see eg here
First off, you can't do this with sqlx, whether or not you're using Postgres arrays.
Second, your SQL query is simply aggregating Post IDs, not the content of the posts, so there's no way to get the data you want (using Go or otherwise).
So here's what you can do:
Use an anonymous embedded struct, capture all of the Post content in your SQL query, and then merge your duplicated Threads.
type Post struct {
Id int `db:"id" json:"id"`
Comment string `db:"comment" json:"comment" binding:"required" form:"comment"`
ProfileId int `db:"profile_id" json:"profile_id" binding:"required" form:"profile_id"`
ThreadId int `db:"thread_id" json:"thread_id" binding:"required" form:"thread_id"`
}
type ThreadDb struct {
Id int `db:"id" json:"id"`
Name string `db:"name" json:"name" binding:"required" form:"name"`
ProfileId int `db:"profile_id" json:"profile_id" binding:"required" form:"profile_id"`
Post
}
type Thread struct {
Id int `db:"id" json:"id"`
Name string `db:"name" json:"name" binding:"required" form:"name"`
ProfileId int `db:"profile_id" json:"profile_id" binding:"required" form:"profile_id"`
Posts []Post `db:"posts" json:"posts" form:"posts"`
}
func GetThreads(db *sqlx.DB, c *gin.Context) {
threads := []ThreadDb{}
err := db.Select(&threads, `
SELECT thread.id,thread.name,thread.profile_id,post.id,post.comment,post.profile_id,post.thread_id
FROM thread
INNER JOIN post ON thread.id = post.thread_id
GROUP BY post.id;
`)
thread_map := make(map[string]Thread)
for i, thread := range threads {
if _, ok := thread_map[thread.Id]; ok {
thread_map[thread.Id].Posts = append(thread_map[thread.Id].Posts, thread.Post)
} else {
thread_map[thread.Id] = Thread{thread.Id, thread.Name, thread.ProfileId, []Post{thread.Post}}
}
}
var threadSlice []string
for k := range thread_map {
threadSlice = append(threadSlice, k)
}
if err != nil {
log.Fatal(err)
}
c.JSON(http.StatusOK, gin.H{"data": threadSlice})
}
Use GROUP_CONCAT or similar. I wouldn't recommend unless you plan on having a maximum of about 100 posts per thread.

Select from two tables with gorm

I'm using gorm and postgresql for a side-project, and I don't know how to solve this problem in 1 request:
My User type is the following:
type User struct {
UserId string
Email string
FirstName string
LastName string
Phone string
Address_1 string
Address_2 string
City string
State string
Zip string
Gender string
ImageUri string
Roles []Role `gorm:"foreignkey:UserId"`
}
My Role type is the following:
type Role struct {
UserId string
Role string
}
I want to get all users with their associated roles, but right now i'm doing this with 2 requests and I want to do it only with one:
func (s *Store) ListUsers() ([]User, error) {
users := []User{}
if err := db.Joins("join roles ON roles.user_id = users.user_id").Find(&users).Error; err != nil {
return nil, err
}
for i, user := range users {
roles := []Role{}
if err := db.Where("user_id = ?", user.UserId).Model(&Role{}).Find(&roles).Error; err != nil {
return User{}, errors.Wrap(err, "failed to get roles")
}
users[i].Roles = roles
}
return users, nil
}
I tried with several different requests, using Related etc... but my Roles slice is always empty. Any ideas ?
[EDIT] My sql schema
CREATE TABLE IF NOT EXISTS users (
user_id varchar PRIMARY KEY UNIQUE NOT NULL,
email varchar UNIQUE NOT NULL,
first_name varchar,
last_name varchar,
phone varchar,
address_1 varchar,
address_2 varchar,
city varchar,
state varchar,
zip varchar,
gender varchar,
image_uri varchar
);
CREATE TABLE IF NOT EXISTS roles (
user_id varchar REFERENCES users (user_id) ON DELETE CASCADE,
role varchar NOT NULL
);
There #har07 soultions it's probably what you need db.Preload("Roles").Find(&users) but you can't get Roles because you don't have primary key declared in you user struct, so at the end your user should look like this:
type User struct {
UserId string `gorm:"primary_key"`
Email string
FirstName string
LastName string
Phone string
Address_1 string
Address_2 string
City string
State string
Zip string
Gender string
ImageUri string
Roles []Role `gorm:"foreignkey:UserId"`
}