How to use results from a sql query as a variable - mysql

I'm trying to use a result from a query as an integer, so i can use it in some different calculations.
I'm fairly new at Go and programming in general(really new, just started school a few weeks back). For an assignment for school I need to calculate the 'doorlooptijd'(nr of months a customer has to pay) based on the customers age.
When i run below code i keep getting the error: 'cannot use leeftijdAlsText (type *sql.Rows) as type string in argument to strconv.Atoi'
leeftijd := "SELECT TIMESTAMPDIFF(YEAR, k.geboortedatum, NOW()) AS leeftijd FROM klant k WHERE k.klantnummer = ?"
leeftijdAlsText, err := db.Query(leeftijd, nummerKlant)
if err != nil {
fmt.Println("Error found.")
panic(err)
}
var huidigeLeeftijd int
if leeftijdAlsText.Next() {
err := leeftijdAlsText.Scan(&leeftijdAlsText)
if err != nil {
fmt.Println("Error found")
panic(err)
}
}
huidigeLeeftijd, _ = strconv.Atoi(leeftijdAlsText)
var doorlooptijd int
if huidigeLeeftijd < 45 {
doorlooptijd = 120
} else if huidigeLeeftijd > 45 && huidigeLeeftijd < 55 {
doorlooptijd = 90
} else if huidigeLeeftijd > 55 {
doorlooptijd = 60
}
When this works, i need to insert the doorlooptijd in a new row in my database, together with some other information about the customer.

Related

Gorm mariadb cache query select in transaction

I use gorm and mariadb
there is a function to update to the terminal table and insert to the terminalLog table.
by using the transaction begin commit . before inserting I checked the terminalLog table by calling the GetByUniqueTerminalLog function.
If the GetByUniqueTerminalLog function is placed before the transaction begin, it returns the query result data.
but if the function is between the transaction begin and commit it does not return the data that was previously inserted into the terminalLog table.
what caused it?
what should i do if GetByUniqueTerminalLog is placed between transactions begin commit.
this is the source code snippet
func (r *TerminalRepository) GetByUniqueTerminalLog(ctx *gin.Context, id int64, terminal_id int64, version string, device_id string, payment_id int64) (res *model.TerminalLog, err error) {
log.Debug("TerminalRepository - GetByUniqueTerminalLog() - starting...")
db := r.DbContext.DB
if id > 0 {
db = db.Where("id = ?", id)
}
if terminal_id > 0 {
db = db.Where("terminal_id = ? ", terminal_id)
}
if payment_id > 0 {
db = db.Where("payment_id = ? ", payment_id)
}
if device_id != "" {
db = db.Where("device_id = ? ", device_id)
}
if version != "" {
db = db.Where("version = ? ", version)
}
result := db.Debug().Find(&res)
if result.Error != nil {
return res, result.Error
}
log.Debug("TerminalRepository - GetByUniqueTerminalLog() - finished.")
return res, nil
}
func (r *TerminalRepository) UpdateTerminalVersion(ctx *gin.Context, data *model.Terminal) (err error) {
log.Debug("TerminalRepository - UpdateTerminalVersion() - starting...")
if err = data.Validate(); err != nil {
return err
}
dataUpdate, err := r.GetByUnique(ctx, data.ID, "", 0, "", "")
if err != nil {
return err
}
if dataUpdate.ID < 1 {
return custom.ErrorNotFoundDB(data.TableName(), "id", data.ID)
}
TerminalLog ,err := r.GetByUniqueTerminalLog(ctx,0,dataUpdate.ID,data.Version,"",0)
dataUpdate.Version = data.Version
dataUpdate.InitAudit(constant.OPERATION_SQL_UPDATE, data.UpdatedUser)
tx := r.DbContext.DB.Begin()
result := tx.Updates(&dataUpdate)
if result.Error != nil {
tx.Rollback()
return result.Error
}
if result.RowsAffected < 1 {
tx.Rollback()
return custom.ErrorOperationDB(dataUpdate.TableName(), "update")
}
//TerminalLog ,err := r.GetByUniqueTerminalLog(ctx,0,dataUpdate.ID,data.Version,"",0)
fmt.Printf("TerminalLog %+v\n ",TerminalLog)
if TerminalLog.ID < 1 {
DataTerminalLog := model.TerminalLog{
Version: data.Version,
Activity: "UPDATE_VERSION",
TerminalId: &dataUpdate.ID,
MerchantId: &dataUpdate.MerchantId,
PaymentId: dataUpdate.PaymentId,
DeviceId: dataUpdate.DeviceId,
}
DataTerminalLog.InitAudit(constant.OPERATION_SQL_INSERT, 1)
resultInsertLog := tx.Create(&DataTerminalLog)
if resultInsertLog.Error != nil {
tx.Rollback()
return resultInsertLog.Error
}
if resultInsertLog.RowsAffected < 1 {
tx.Rollback()
return custom.ErrorOperationDB(dataUpdate.TableName(), "insert")
}
}
tx.Commit()
log.Debug("TerminalRepository - UpdateTerminalVersion() - finished.")
return nil
}

Running aggregate join queries on mysql from golang returns no values

I have the following query which returns results when run directly from mysql.
The same query returns 0 values, when run from golang program.
package main
import (
"github.com/rs/zerolog/log"
_ "github.com/go-sql-driver/mysql"
"github.com/jmoiron/sqlx"
)
var DB *sqlx.DB
func main() {
DB, err := sqlx.Connect("mysql", "root:password#(localhost:3306)/jsl2")
if err != nil {
log.Error().Err(err)
}
sqlstring := `SELECT
salesdetails.taxper, sum(salesdetails.gvalue),
sum(salesdetails.taxamt)
FROM salesdetails
Inner Join sales ON sales.saleskey = salesdetails.saleskey
where
sales.bdate >= '2021-12-01'
and sales.bdate <= '2021-12-31'
and sales.achead IN (401975)
group by salesdetails.taxper
order by salesdetails.taxper`
rows, err := DB.Query(sqlstring)
for rows.Next() {
var taxper int
var taxableValue float64
var taxAmount float64
err = rows.Scan(&taxper, &taxableValue, &taxAmount)
log.Print(taxper, taxableValue, taxAmount)
}
err = rows.Err()
if err != nil {
log.Error().Err(err)
}
}
On the console, running the program returns the following values.
In SQL browser, it returns 4 rows which is correct.
The result from the sql browser for the same query is
0 1278.00 0.00
5 89875.65 4493.78
12 3680.00 441.60
18 94868.73 17076.37
But in the program also return 4 rows with 0 value.
{"level":"debug","time":"2022-01-13T17:07:39+05:30","message":"0 0 0"}
{"level":"debug","time":"2022-01-13T17:07:39+05:30","message":"0 0 0"}
{"level":"debug","time":"2022-01-13T17:07:39+05:30","message":"0 0 0"}
{"level":"debug","time":"2022-01-13T17:07:39+05:30","message":"0 0 0"}
How to set the datatype for the aggregate functions.
I changed the datatype of taxper to float and it worked.
I found this after checking the err from rows.Scan( as suggested by #mkopriva

sql.Query truncated or incomplete results

I've the following code:
const qInstances = `
SELECT
i.uuid,
i.host,
i.hostname
FROM
db.instances AS i
WHERE
i.deleted_at IS NULL
GROUP BY i.uuid;
`
...
instancesMap := make(map[string]*models.InstanceModel)
instances := []models.Instance{}
instancesCount := 0
instancesRow, err := db.Query(qInstances)
if err != nil {
panic(err.Error())
}
defer instancesRow.Close()
for instancesRow.Next() {
i := models.Instance{}
err = instancesRow.Scan(&i.UUID, &i.Host, &i.Hostname)
if err != nil {
log.Printf("[Error] - While Scanning Instances Rows, error msg: %s\n", err)
panic(err.Error())
} else {
if i.UUID.String != "" {
instancesCount++
}
if _, ok := instancesMap[i.UUID.String]; !ok {
instancesMap[i.UUID.String] = &models.InstanceModel{}
inst := instancesMap[i.UUID.String]
inst.UUID = i.UUID.String
inst.Host = i.Host.String
inst.Hostname = i.Hostname.String
} else {
inst := instancesMap[i.UUID.String]
inst.UUID = i.UUID.String
inst.Host = i.Host.String
inst.Hostname = i.Hostname.String
}
instances = append(instances, i)
}
}
log.Printf("[Instances] - Total Count: %d\n", instancesCount)
The problem that I'm facing is that if run the SQL query directly to the database (mariadb) it returns 7150 records, but the total count inside the program outputs 5196 records. I also check the SetConnMaxLifetime parameter for the db connection and set it to 240 seconds, and it doesn't show any errors or broken connectivity between the db and the program. Also I try to do some pagination (LIMIT to 5000 records each) and issue two different queries and the first one returns the 5000 records, but the second one just 196 records. I'm using the "github.com/go-sql-driver/mysql" package. Any ideas?

Does gorm shares an ID from previous transaction Create

I have a query, that requires ID from the previous insert. Does gorm gives away the ID in transaction mode:
Example:
err := db.Transaction(func(tx *gorm.DB) error {
if err := tx.Model(&model.user).Create(&user).Error; err != nil {
tx.Rollback()
}
// if user inserted get the user ID from previous user insert of DB
for _, v := profiles {
v.UserID = user.ID // Can I get this ID from previous Create operation?
}
if err := tx.Model(&model.profile).Create(&profiles).Error; err != nil {
tx.Rollback()
}
})
Yes, you can use the Find function toget the data that you created.
if err := tx.Model(&model.profile).Create(&profiles).Find(&profiles).Error; err != nil {
tx.Rollback()
}

How can i Check if my Db.Query returns null rows

Following is my code to get multiple rows from db and it works.
defer db.Close()
for rows.Next() {
err = rows.Scan(&a)
if err != nil {
log(err)
}
How can I check if the rows contains No row?
Even I tried like below
if err == sql.ErrNoRows {
fmt.Print(No rows)
}
and also checked while scanning
err = rows.Scan(&a)
if err == sql.ErrNoRows {
fmt.Print(No rows)
}
I don't understand which one gives ErrNoRows either *Rows or err or Scan
QueryRow returns a *Row (not a *Rows) and you cannot iterate through the results (because it's only expecting a single row back). This means that rows.Scan in your example code will not compile).
If you expect your SQL query to return a single resullt (e.g. you are running a count() or selecting using an ID) then use QueryRow; for example (modified from here):
id := 43
var username string
err = stmt.QueryRow("SELECT username FROM users WHERE id = ?", id).Scan(&username)
switch {
case err == sql.ErrNoRows:
log.Fatalf("no user with id %d", id)
case err != nil:
log.Fatal(err)
default:
log.Printf("username is %s\n", username)
}
If you are expecting multiple rows then use Query() for example (modified from here):
age := 27
rows, err := db.Query("SELECT name FROM users WHERE age=?", age)
if err != nil {
log.Fatal(err)
}
defer rows.Close()
names := make([]string, 0)
for rows.Next() {
var name string
if err := rows.Scan(&name); err != nil {
log.Fatal(err)
}
names = append(names, name)
}
// Check for errors from iterating over rows.
if err := rows.Err(); err != nil {
log.Fatal(err)
}
// Check for no results
if len(names) == 0 {
log.Fatal("No Results")
}
log.Printf("%s are %d years old", strings.Join(names, ", "), age)
The above shows one way of checking if there are no results. If you are not putting the results into a slice/map then you can keep a counter or set a boolean within the loop. Note that no error will be returned if there are no results (because this is a perfectly valid outcome) and the SQL package provides no way to check the number of results other than iterate through them (if all you are interested in is the number of results then run select count(*)...).