-
Notifications
You must be signed in to change notification settings - Fork 843
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support passing slices to MySQL queries #695
Comments
Here's some related discussion from the go-sql-driver repository: |
The MEMBER OF syntax may offer a solution. The problem is that you need to encode the slice as JSON before passing it into the query. CREATE TABLE pkg (
id text NOT NULL,
vic VARCHAR(50) NOT NULL,
kim text NOT NULL,
order INTEGER NOT NULL,
PRIMARY KEY (id)
);
/* name: GetPkgID :many */
SELECT id, vic, kim FROM pkg
WHERE vic MEMBER OF(?) AND shop_id = ?; |
Okay, here's my current idea. We add a second type parameter to CREATE TABLE users (id SERIAL);
-- name: FilterUsers :many
SELECT * FROM users
WHERE id MEMBER OF(sqlc.arg('ids', 'SERIAL ARRAY')); const filterUsers = `-- name: FilterUsers :many
SELECT id FROM users
WHERE id MEMBER OF(CAST(? AS JSON));
`
func (q *Queries) FilterUsers(ctx context.Context, ids []int64) ([]User, error) {
// ...
} A few issues I can think of:
|
I'm not sure if it's bad practice, but maybe the generated code could produce a dynamic query, generating N placeholders for each array value. So, something like: func filterUsers(vals []interface{})
{
return fmt.Sprintf(`-- name: FilterUsers :many
SELECT id FROM users
WHERE id IN (?%v);
`, strings.Repeat(",?", len(vals)-1));
} |
Just throwing an idea (or hack) regarding Current behaviour: const listAuthors = `-- name: ListAuthors :many
SELECT id, name FROM authors WHERE id IN($1) AND name = $2;
`
type ListAuthorsParams struct {
ID int
Name string
}
func (q *Queries) ListAuthors(ctx context.Context, arg ListAuthorsParams) ([]Author, error) {
rows, err := q.db.QueryContext(ctx, listAuthors, arg.ID, arg.Name) My idea is to change the parameter into slice and expanding the query based on the size of the slice. type ListAuthorsParams struct {
ID []int
Name string
}
func (q *Queries) ListAuthors(ctx context.Context, arg ListAuthorsParams) ([]Author, error) {
query, args := q.expand(listAuthors, expandArg{arg.ID}, arg.Name)
rows, err := q.db.QueryContext(ctx, query, args...) The For example, given that query = "SELECT id, name FROM authors WHERE id IN($1, $2, $3, $4) AND name = $5;"
args = []interface{}{9, 8, 6, 7, "Joe"} The code for Not forget to mention, this solution will not work for prepared statement. |
How about for MySQL only, Pros
Cons
|
Hi @kyleconroy, Good your idea. But
Syntax error with keyword |
I have an idea, using FIND_IN_SET
But name of variable after run |
How can I achieve this in postgres? |
i fufill a version that solve this problem https://github.com/xiazemin/sqlc |
Is there a workaround for the time? Listing by IDs seems to be a rather crucial thing to do after all, e.g. for pre-loading associations |
The only work around I ended up doing was creating a separate file that shares the same package name and writing the golang code manually :/ |
This feature (currently MySQL-specific) allows passing in a slice to an IN clause. Adding the new function sqlc.slice() as opposed to overloading the parsing of "IN (?)" was chosen to guarantee backwards compatibility. SELECT * FROM tab WHERE col IN (sqlc.slice("go_param_name")) The MySQL FLOAT datatype mapping has been added too.
This feature (currently MySQL-specific) allows passing in a slice to an IN clause. Adding the new function sqlc.slice() as opposed to overloading the parsing of "IN (?)" was chosen to guarantee backwards compatibility. SELECT * FROM tab WHERE col IN (sqlc.slice("go_param_name")) The MySQL FLOAT datatype mapping has been added too.
my fork solved this issue https://github.com/xiazemin/sqlc |
and the example of https://github.com/xiazemin/sqlc is here https://github.com/xiazemin/sqlc_study |
hey @xiazemin this is great! Just read your previous messages also, maybe you can make a proposal or pull request to this repo? I recommend contributing to this git repository instead of branching with your fork because your fork seems to be missing a ton of features. |
@kyleconroy Hi, any plan to support slice? |
A good solution to this is crucial. There is an acceptable solution for the postgres driver using pg.Array() but in the comment thread above there was nothing that really works for mysql. In the meantime, I'll fall back to using a query generator like squirrel but that's not my first choice. |
I've been using a forked version of sqlc where they implemented |
my fork also support insert into xxx values xxx, where values is a slice,you can try it! |
Xiazemin, your sqlc repo renames everything and is not a true fork, your code can’t be migrated back into the main repository.
… On May 31, 2022, at 8:49 AM, xiazemin ***@***.***> wrote:
https://github.com/xiazemin/sqlc <https://github.com/xiazemin/sqlc>
—
Reply to this email directly, view it on GitHub <#695 (comment)>, or unsubscribe <https://github.com/notifications/unsubscribe-auth/AAAKW6GUNJEE2FNROJSWWBLVMYYITANCNFSM4QPX4D2Q>.
You are receiving this because you commented.
|
When will this feature be updated? |
SELECT * FROM a_table WHERE (a, b) in (?); How to implement this case in sqlc? |
Hello, this seems like a pretty important feature to have. Anybody have a plan to implement this? If somebody can point me to the correct place I can try submitting a PR. Thanks |
It works in Postgresql
|
Thanks @chengjun-suger I tried with -- name: SelectWhereInLastNames :many
SELECT * FROM users WHERE last_name = ANY(@last_name::text[]); and it generates import (
"context"
"database/sql"
"encoding/json"
"github.com/lib/pq"
)
const selectWhereInLastNames = `-- name: SelectWhereInLastNames :many
SELECT id, first_name, middle_name, last_name, email, password, favourite_colour FROM users WHERE last_name = ANY($1::text[])
`
func (q *Queries) SelectWhereInLastNames(ctx context.Context, lastName []string) ([]User, error) {
rows, err := q.db.QueryContext(ctx, selectWhereInLastNames, pq.Array(lastName))
if err != nil {
return nil, err
}
defer rows.Close()
var items []User
for rows.Next() {
var i User
if err := rows.Scan(
&i.ID,
&i.FirstName,
&i.MiddleName,
&i.LastName,
&i.Email,
&i.Password,
&i.FavouriteColour,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Close(); err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
} |
This feature (currently MySQL-specific) allows passing in a slice to an IN clause. Adding the new function sqlc.slice() as opposed to overloading the parsing of "IN (?)" was chosen to guarantee backwards compatibility. SELECT * FROM tab WHERE col IN (sqlc.slice("go_param_name")) This commit is based on sqlc-dev#1312 by Paul Cameron. I just rebased and did some cleanup. Co-authored-by: Paul Cameron <[email protected]>
This feature (currently MySQL-specific) allows passing in a slice to an IN clause. Adding the new function sqlc.slice() as opposed to overloading the parsing of "IN (?)" was chosen to guarantee backwards compatibility. SELECT * FROM tab WHERE col IN (sqlc.slice("go_param_name")) This commit is based on sqlc-dev#1312 by Paul Cameron. I just rebased and did some cleanup. Co-authored-by: Paul Cameron <[email protected]>
This feature (currently MySQL-specific) allows passing in a slice to an IN clause. Adding the new function sqlc.slice() as opposed to overloading the parsing of "IN (?)" was chosen to guarantee backwards compatibility. SELECT * FROM tab WHERE col IN (sqlc.slice("go_param_name")) This commit is based on sqlc-dev#1312 by Paul Cameron. I just rebased and did some cleanup. Co-authored-by: Paul Cameron <[email protected]>
I see this issue discussed for nearly two years, is there a solution or a plan in the near future, which will determine whether my project can choose to use sqlc instead of others, such as gorm. |
Really want this feature as well and started to think about an alternative approach to the problem. Not sure if this is possible in the way sqlc works, I'm just putting the idea out there to start a discussion. For example, take the following query: -- name: FindThings :many :variadric(0)
SELECT *
FROM a_table
WHERE status IN ( ? )
AND created_at > ? This would tell sqlc that the first Would this be possible with the current approach? And if so, does anyone know where to start? |
Hi @karatekaneen, Yes, I should put some manual labor to list the args that using |
@LIQRGV Interesting, going to have a deep dive in the code on Monday to see what you've done. Currently looking to doing something similar to what you've done but as a plugin, but haven't decided anything yet. |
Yep, @karatekaneen technically it's not a valid SQL anymore since it'll parse the query into another placeholder depend on the number args passed. Anyway, do you know how to use |
This feature (currently MySQL-specific) allows passing in a slice to an IN clause. Adding the new function sqlc.slice() as opposed to overloading the parsing of "IN (?)" was chosen to guarantee backwards compatibility. SELECT * FROM tab WHERE col IN (sqlc.slice("go_param_name")) This commit is based on sqlc-dev#1312 by Paul Cameron. I just rebased and did some cleanup. Co-authored-by: Paul Cameron <[email protected]>
This feature (currently MySQL-specific) allows passing in a slice to an IN clause. Adding the new function sqlc.slice() as opposed to overloading the parsing of "IN (?)" was chosen to guarantee backwards compatibility. SELECT * FROM tab WHERE col IN (sqlc.slice("go_param_name")) This commit is based on sqlc-dev#1312 by Paul Cameron. I just rebased and did some cleanup. Co-authored-by: Paul Cameron <[email protected]>
FIND_IN_SET does the job |
This waits for #1816 to be reviewed and merged. |
This feature (currently MySQL-specific) allows passing in a slice to an IN clause. Adding the new function sqlc.slice() as opposed to overloading the parsing of "IN (?)" was chosen to guarantee backwards compatibility. SELECT * FROM tab WHERE col IN (sqlc.slice("go_param_name")) This commit is based on sqlc-dev#1312 by Paul Cameron. I just rebased and did some cleanup. Co-authored-by: Paul Cameron <[email protected]>
This feature (currently MySQL-specific) allows passing in a slice to an IN clause. Adding the new function sqlc.slice() as opposed to overloading the parsing of "IN (?)" was chosen to guarantee backwards compatibility. SELECT * FROM tab WHERE col IN (sqlc.slice("go_param_name")) This commit is based on #1312 by Paul Cameron. I just rebased and did some cleanup. Co-authored-by: Paul Cameron <[email protected]>
Can this not be closed now that #1816 is merged? |
https://docs.sqlc.dev/en/stable/reference/macros.html#sqlc-slice Adding a link to the docs for future folks |
@kyleconroy #2002 was marked as a duplicate of this issue. #2002 concerns multiple inserted values. sqlc.slice can't be used for that purpose as it replaces name by multuplie escaped params entries of type string. We have this other issue #3305 that is open that explains it better IMHO. |
While MySQL supports the ANY operator, it does not support arrays. This means the currently documented way to pass slices to a query will not work.
The text was updated successfully, but these errors were encountered: