In my Golang application I make SQL request to the database. Usually, in the SQL query, I specify the columns that I want to get from the table and create a structure based on it. You can see an example of the working code below.
QUESTION:
What should I do if I don’t know the number and name of columns in the table? For example, I make the SQL request like SELECT * from filters;
instead of SELECT FILTER_ID, FILTER_NAME FROM filters;
. How do I create a structure in this case?
var GetFilters = func(responseWriter http.ResponseWriter, request *http.Request) { rows, err := database.ClickHouse.Query("SELECT * FROM filters;"); if err != nil { fmt.Println(err) return } defer rows.Close() columns, err := rows.Columns(); if err != nil { fmt.Println(err) return } filters := make([]interface{}, len(columns)) for i, _ := range columns { filters[i] = new(sql.RawBytes) } for rows.Next() { if err = rows.Scan(filters...); err != nil { fmt.Println(err) return } } utils.Response(responseWriter, http.StatusOK, filters) }
Advertisement
Answer
Well, finally I found the solution. As you can see from the code below first I make SQL request where I do not specify the name of the columns. Then I take information about columns by ColumnTypes()
function. This function returns column information such as column type, length and nullable. Next I will learn the name and type of columns, fill interface with these data:
for i, column := range columns { object[column.Name()] = reflect.New(column.ScanType()).Interface() values[i] = object[column.Name()] }
The full code which I use looks like this:
var GetFilters = func(responseWriter http.ResponseWriter, request *http.Request) { rows, err := database.ClickHouse.Query("SELECT * FROM table_name;"); if err != nil { fmt.Println(err) return } defer rows.Close() var objects []map[string]interface{} for rows.Next() { columns, err := rows.ColumnTypes(); if err != nil { fmt.Println(err) return } values := make([]interface{}, len(columns)) object := map[string]interface{}{} for i, column := range columns { object[column.Name()] = reflect.New(column.ScanType()).Interface() values[i] = object[column.Name()] } if err = rows.Scan(values...); err != nil { fmt.Println(err) return } objects = append(objects, object) } utils.Response(responseWriter, http.StatusOK, objects) }