type Post struct {
ID int64
Title string
Text string
}
type UserPosts struct {
Username string
Posts []Post
}
func qna864719(db *sql.DB) ([]UserPosts, error) {
query := `select u.username
, p.post_id
, p.post_title
, p.post_text
from posts p
join users u on u.user_id = p.post_author
group by u.username, p.post_id;`
rows, err := db.Query(query)
if err != nil {
return nil, fmt.Errorf("query: %w", err)
}
defer rows.Close()
var result []UserPosts
for rows.Next() {
var username string
var post Post
err = rows.Scan(&username, &post.ID, &post.Title, &post.Text)
if err != nil {
return nil, fmt.Errorf("scan: %w", err)
}
// Здесь логика преобразования результата в массив UserPosts
}
err = rows.Err()
if err != nil {
return nil, fmt.Errorf("after scan: %w", err)
}
return result, nil
}
func qna864719_1(db *sql.DB) ([]UserPosts, error) {
query := `select u.username
, p.post_id
, p.post_title
, p.post_text
from posts p
join users u on u.user_id = p.post_author
group by u.username, p.post_id
order by u.username` // <-------- ОБЯЗАТЕЛЬНАЯ СОРТИРОВКА
rows, err := db.Query(query)
if err != nil {
return nil, fmt.Errorf("query: %w", err)
}
defer rows.Close()
var result []UserPosts
// Храним промежуточный результат по юзеру в переменной,
// перед добавлением в основной массив
var lastResult *UserPosts // <--------
for rows.Next() {
var username string
var post Post
err = rows.Scan(&username, &post.ID, &post.Title, &post.Text)
if err != nil {
return nil, fmt.Errorf("scan: %w", err)
}
// Здесь логика преобразования результата в массив UserPosts
// Если промежуточный результат существует, но username отличается
// от текущего, то добавляем промежуточный результат в основной массив
// обнуляя промежуточный результат
if lastResult != nil && lastResult.Username != username {
result = append(result, *lastResult)
lastResult = nil
}
// Если промежуточного результата нет, иницилизируем его
if lastResult == nil {
lastResult = &UserPosts{Username: username}
}
// Добавляем посты
lastResult.Posts = append(lastResult.Posts, post)
}
err = rows.Err()
if err != nil {
return nil, fmt.Errorf("after scan: %w", err)
}
// После выхода из сканирования, у нас может остаться промежуточный результат
// который необходимо добавить в основной массив
if lastResult != nil {
result = append(result, *lastResult)
}
return result, nil
}
func qna864719_2(db *sql.DB) ([]UserPosts, error) {
query := `select u.username
, p.post_id
, p.post_title
, p.post_text
from posts p
join users u on u.user_id = p.post_author
group by u.username, p.post_id;`
rows, err := db.Query(query)
if err != nil {
return nil, fmt.Errorf("query: %w", err)
}
defer rows.Close()
var result []UserPosts
// Иницилизируем хеш-мап который будет содержать посты по username
postsByUsername := make(map[string][]Post)
for rows.Next() {
var username string
var post Post
err = rows.Scan(&username, &post.ID, &post.Title, &post.Text)
if err != nil {
return nil, fmt.Errorf("scan: %w", err)
}
// Здесь логика преобразования результата в массив UserPosts
// Добавляем посты в мап
postsByUsername[username] = append(postsByUsername[username], post)
}
err = rows.Err()
if err != nil {
return nil, fmt.Errorf("after scan: %w", err)
}
// Преобразовываем мап в массив
for username, posts := range postsByUsername {
result = append(result, UserPosts{
Username: username,
Posts: posts,
})
}
// Сортируем, так как в мапе записи хранятся в "случайном" порядке
sort.Slice(result, func(i, j int) bool {
return result[i].Username < result[j].Username
})
return result, nil
}