Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
HAVING
— это оператор в SQL, который фильтрует группированные (GROUP BY
) данные по агрегатным функциям (SUM
, COUNT
, AVG
, MAX
, MIN
). WHERE
фильтрует отдельные строки до группировки. HAVING
фильтрует группы строк после GROUP BY
. Теперь посчитаем сумму продаж по категориям и оставим только те, где сумма > 250
SELECT category, SUM(amount) AS total_sales
FROM sales
GROUP BY category
HAVING SUM(amount) > 250;
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
Тип string в Go — это последовательность байтов, закодированных в UTF-8.
Он реализован как структура:
- указатель на массив байтов;
- длина строки.
Строки неизменяемы. Любая операция, которая кажется «изменением», на самом деле создаёт новую строку.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
Это целочисленные значения, которые используются для доступа к элементам упорядоченных структур данных. В контексте Go индексы чаще всего применяются для работы со строками, массивами, срезами, а также картами (косвенно, через ключи).
Индексы позволяют обращаться к конкретным элементам массива, строки или среза. Например, если у нас есть массив чисел, индекс указывает, какой именно элемент извлечь.
С помощью индексов можно перебирать элементы массива, строки или среза, например, используя циклы.
В изменяемых структурах данных, таких как срезы или массивы, индекс позволяет присвоить новое значение конкретному элементу.
Индексы упрощают и ускоряют доступ к данным, потому что доступ осуществляется за O(1) (константное время) в массивах или срезах.
В строках индексы используются для доступа к конкретным байтам.
package main
import "fmt"
func main() {
str := "Привет"
fmt.Println(str[0]) // 208 (байт, не символ!)
fmt.Printf("%c\n", str[0]) // П (символ, представленный первым байтом UTF-8)
}
В массивах и срезах индексы используются для извлечения и изменения значений
package main
import "fmt"
func main() {
arr := [5]int{10, 20, 30, 40, 50}
fmt.Println(arr[2]) // 30
// Изменение значения по индексу
arr[2] = 100
fmt.Println(arr) // [10 20 100 40 50]
}
Обычно индексы используются для итерации по элементам коллекции с помощью цикла
for
.package main
import "fmt"
func main() {
nums := []int{10, 20, 30, 40, 50}
for i, v := range nums {
fmt.Printf("Индекс: %d, Значение: %d\n", i, v)
}
}
Индексы полезны для извлечения подстрок с использованием срезов:
package main
import "fmt"
func main() {
str := "Привет, Мир!"
fmt.Println(str[8:12]) // Мир
}
Если попытаться обратиться к элементу по индексу, который выходит за пределы коллекции, Go выдаст runtime panic:
package main
func main() {
nums := []int{1, 2, 3}
fmt.Println(nums[5]) // panic: runtime error: index out of range
}
Если неверно учитывать байтовое представление символов UTF-8, можно получить некорректный результат.
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
- Фиксировать транзакции быстрее – минимизировать время блокировки.
- Обращаться к таблицам в одном порядке во всех транзакциях.
- Использовать LOCK TABLES осторожно – избегать чрезмерного блокирования.
- Рассмотреть уровень изоляции – READ COMMITTED или REPEATABLE READ могут уменьшить вероятность дедлоков.
- Анализировать логи и SHOW ENGINE INNODB STATUS для выявления конфликтов.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2🔥2
HAVING
— это оператор SQL, который фильтрует результаты после GROUP BY
, аналогично WHERE
, но работает с агрегатными функциями (COUNT()
, SUM()
, AVG()
, MAX()
, MIN()
). WHERE
фильтрует до GROUP BY
(по отдельным строкам). HAVING
фильтрует после GROUP BY
(по сгруппированным данным). Пример 1: Фильтрация по
HAVING
Задача: Вывести товары, у которых продано более 10 единиц.
SELECT product, SUM(quantity) as total_sold
FROM sales
GROUP BY product
HAVING SUM(quantity) > 10;
Пример 2: Разница между
WHERE
и HAVING
SELECT category, COUNT(*) as total_products
FROM products
WHERE price > 100 -- ❌ Убирает дешёвые товары ДО группировки
GROUP BY category
HAVING COUNT(*) > 5; -- ✅ Оставляет только категории с более 5 товаров
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
В Go есть два способа объявления переменной:
1. Быстрое объявление (:=) — используется внутри функций, тип выводится автоматически:
2. name := "Alice"
3. Объявление через var — даёт больше контроля, можно использовать вне функции и указывать тип:
4. var age int = 30
5. var city string
Краткое объявление невозможно на уровне пакета и не подходит для заранее объявленных, но ещё не инициализированных переменных.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
В контексте gRPC (Google Remote Procedure Call) unary и stream — это два разных типа взаимодействия между клиентом и сервером.
это стандартный запрос-ответ:
Клиент отправляет одно сообщение → сервер отвечает одним сообщением.
service UserService {
rpc GetUserInfo(UserRequest) returns (UserResponse);
}
Go-реализация Unary RPC
func (s *server) GetUserInfo(ctx context.Context, req *pb.UserRequest) (*pb.UserResponse, error) {
user := &pb.UserResponse{
Id: req.Id,
Name: "John Doe",
Email: "john@example.com",
}
return user, nil // Обычный ответ
}
В streaming RPC передача данных идёт потоком. gRPC поддерживает три вида стримов:
Клиент отправляет один запрос → сервер возвращает поток ответов.
service UserService {
rpc GetUserActivity(UserRequest) returns (stream ActivityResponse);
}
Go-реализация Server Streaming
func (s *server) GetUserActivity(req *pb.UserRequest, stream pb.UserService_GetUserActivityServer) error {
activities := []string{"Login", "Upload File", "Logout"}
for _, activity := range activities {
err := stream.Send(&pb.ActivityResponse{Message: activity})
if err != nil {
return err
}
time.Sleep(time.Second) // Имитация задержки
}
return nil
}
Клиент отправляет поток данных → сервер отвечает одним ответом.
service UploadService {
rpc UploadFile(stream FileChunk) returns (UploadResponse);
}
Go-реализация Client Streaming
func (s *server) UploadFile(stream pb.UploadService_UploadFileServer) error {
var totalSize int64
for {
chunk, err := stream.Recv()
if err == io.EOF {
return stream.SendAndClose(&pb.UploadResponse{Size: totalSize})
}
if err != nil {
return err
}
totalSize += chunk.Size
}
}
Клиент и сервер обмениваются данными в потоке одновременно.
service ChatService {
rpc Chat(stream ChatMessage) returns (stream ChatMessage);
}
Go-реализация Bi-directional Streaming
func (s *server) Chat(stream pb.ChatService_ChatServer) error {
for {
msg, err := stream.Recv()
if err == io.EOF {
return nil
}
if err != nil {
return err
}
response := &pb.ChatMessage{Text: "Echo: " + msg.Text}
if err := stream.Send(response); err != nil {
return err
}
}
}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
Это ситуация, когда две или более транзакции блокируют друг друга, ожидая ресурс, который уже заблокирован другой транзакцией. Это приводит к зависанию операций и невозможности завершить выполнение запросов.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
В Go, проверка типа интерфейса может быть выполнена несколькими способами: с помощью утверждения типа (type assertion) и с помощью конструкции
switch
для выбора типа. Утверждение типа позволяет проверить, является ли значение определенного интерфейса конкретным типом. Если да, то оно преобразует интерфейс в этот тип.
value, ok := interfaceValue.(ConcreteType)
value
Значение типа
ConcreteType
, если утверждение типа успешно.ok
Булевое значение, указывающее, удалось ли преобразование.
package main
import "fmt"
func main() {
var i interface{} = "hello"
// Утверждение типа
s, ok := i.(string)
if ok {
fmt.Println("String:", s)
} else {
fmt.Println("Not a string")
}
// Утверждение типа, которое вызовет панику, если тип не соответствует
// Uncomment the line below to see the panic
// s := i.(string)
// fmt.Println(s)
}
Конструкция
switch
позволяет проверить значение интерфейса на соответствие нескольким возможным типам.switch v := interfaceValue.(type) {
case ConcreteType1:
// v имеет тип ConcreteType1
case ConcreteType2:
// v имеет тип ConcreteType2
default:
// v имеет другой тип
}
package main
import "fmt"
func printType(i interface{}) {
switch v := i.(type) {
case string:
fmt.Println("String:", v)
case int:
fmt.Println("Integer:", v)
case bool:
fmt.Println("Boolean:", v)
default:
fmt.Printf("Unknown type: %T\n", v)
}
}
func main() {
printType("hello")
printType(42)
printType(true)
printType(3.14)
}
Пример использования для проверки и работы с интерфейсами
package main
import (
"fmt"
)
type Person struct {
Name string
Age int
}
// Реализация интерфейса fmt.Stringer для типа Person
func (p Person) String() string {
return fmt.Sprintf("%s (%d years old)", p.Name, p.Age)
}
func printValue(i interface{}) {
if str, ok := i.(fmt.Stringer); ok {
fmt.Println("Stringer:", str.String())
} else {
fmt.Println("Not a Stringer")
}
}
func main() {
p := Person{Name: "Alice", Age: 30}
printValue(p) // Проверка типа fmt.Stringer
printValue("Hello, world!") // Строка не реализует fmt.Stringer
}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1