Changes between Version 2 and Version 3 of DatabaseCreation


Ignore:
Timestamp:
05/20/26 15:19:53 (6 days ago)
Author:
231198
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • DatabaseCreation

    v2 v3  
    22
    33=== Имплементациски детали ===
    4 
    54Во овој проект, преку DDL наредби се креирани сите потребни табели за системот за управување со такси апликација, како и нивните меѓусебни релации.
    65
     
    1514=== DDL Скрипти ===
    1615
    17 ```
     16```sql
    1817CREATE TABLE Status (
    19                         status_id SERIAL PRIMARY KEY,
    20                         status_tip VARCHAR(255) NOT NULL,
    21                         status_text VARCHAR(255) NOT NULL
    22 );
    23                                                 
     18    status_id SERIAL PRIMARY KEY,
     19    status_tip VARCHAR(255) NOT NULL,
     20    status_text VARCHAR(255) NOT NULL
     21);
     22                                               
    2423CREATE TABLE Vehicles_model (
    25                                 Vehicles_model_id SERIAL PRIMARY KEY,
    26                                 Model VARCHAR(255) NOT NULL
    27 );
    28                                                 
     24    Vehicles_model_id SERIAL PRIMARY KEY,
     25    Model VARCHAR(255) NOT NULL
     26);
     27                                               
    2928CREATE TABLE Locations (
    30                            location_id SERIAL PRIMARY KEY,
    31                            latitude NUMERIC(9,6) NOT NULL,
    32                            longitude NUMERIC(9,6) NOT NULL,
    33                            grad VARCHAR(255) NOT NULL,
    34                            naselba VARCHAR(255) NOT NULL,
    35                            ulica VARCHAR(255) NOT NULL,
    36                            broj VARCHAR(255) NOT NULL,
    37                            created_at TIMESTAMP NOT NULL
    38 ); 
     29    location_id SERIAL PRIMARY KEY,
     30    latitude NUMERIC(9,6) NOT NULL,
     31    longitude NUMERIC(9,6) NOT NULL,
     32    grad VARCHAR(255) NOT NULL,
     33    naselba VARCHAR(255) NOT NULL,
     34    ulica VARCHAR(255) NOT NULL,
     35    broj VARCHAR(255) NOT NULL,
     36    created_at TIMESTAMP NOT NULL
     37); 
    3938
    4039CREATE TABLE Users (
    41                        User_id SERIAL PRIMARY KEY,
    42                        name VARCHAR(255) NOT NULL,
    43                        username VARCHAR(255) NOT NULL UNIQUE,
    44                        phone VARCHAR(255) NOT NULL UNIQUE,
    45                        email VARCHAR(255) NOT NULL UNIQUE,
    46                        password_hash TEXT NOT NULL,
    47                        created_at TIMESTAMP NOT NULL,
    48                        status_id INT NOT NULL,
    49 
    50                        CONSTRAINT chk_users_phone CHECK (phone ~ '^[0-9+]+$'),
    51                        CONSTRAINT chk_users_email CHECK (email ~ '^[^@]+@[^@]+\.[^@]+$'),
    52 
    53                        CONSTRAINT FK_Users_Status
    54                            FOREIGN KEY (status_id) REFERENCES Status(status_id)
    55                                ON DELETE RESTRICT
    56                                ON UPDATE CASCADE
     40    User_id SERIAL PRIMARY KEY,
     41    name VARCHAR(255) NOT NULL,
     42    username VARCHAR(255) NOT NULL UNIQUE,
     43    phone VARCHAR(255) NOT NULL UNIQUE,
     44    email VARCHAR(255) NOT NULL UNIQUE,
     45    password_hash TEXT NOT NULL,
     46    created_at TIMESTAMP NOT NULL,
     47    status_id INT NOT NULL,
     48
     49    CONSTRAINT chk_users_phone CHECK (phone ~ '^[0-9+]+$'),
     50    CONSTRAINT chk_users_email CHECK (email ~ '^[^@]+@[^@]+\.[^@]+$'),
     51
     52    CONSTRAINT FK_Users_Status
     53        FOREIGN KEY (status_id) REFERENCES Status(status_id)
     54            ON DELETE RESTRICT
     55            ON UPDATE CASCADE
    5756);
    5857
    5958CREATE TABLE Drivers (
    60                          driver_id SERIAL PRIMARY KEY,
    61                          name VARCHAR(255) NOT NULL,
    62                          phone VARCHAR(255) NOT NULL UNIQUE,
    63                          license_number VARCHAR(255) NOT NULL UNIQUE,
    64                          registration_date DATE NOT NULL,
    65                          rating NUMERIC(3,2) NOT NULL,
    66                          status_id INT NOT NULL,
    67 
    68                          CONSTRAINT chk_drivers_phone CHECK (phone ~ '^[0-9+]+$'),
    69                          CONSTRAINT chk_drivers_rating CHECK (rating BETWEEN 0 AND 5),
    70 
    71                          CONSTRAINT FK_Drivers_Status
    72                              FOREIGN KEY (status_id) REFERENCES Status(status_id)
    73                                  ON DELETE RESTRICT
    74                                  ON UPDATE CASCADE
     59    driver_id SERIAL PRIMARY KEY,
     60    name VARCHAR(255) NOT NULL,
     61    phone VARCHAR(255) NOT NULL UNIQUE,
     62    license_number VARCHAR(255) NOT NULL UNIQUE,
     63    registration_date DATE NOT NULL,
     64    rating NUMERIC(3,2) NOT NULL,
     65    status_id INT NOT NULL,
     66
     67    CONSTRAINT chk_drivers_phone CHECK (phone ~ '^[0-9+]+$'),
     68    CONSTRAINT chk_drivers_rating CHECK (rating BETWEEN 0 AND 5),
     69
     70    CONSTRAINT FK_Drivers_Status
     71        FOREIGN KEY (status_id) REFERENCES Status(status_id)
     72            ON DELETE RESTRICT
     73            ON UPDATE CASCADE
    7574);
    7675
    7776CREATE TABLE Admins (
    78                         admins_id SERIAL PRIMARY KEY,
    79                         name VARCHAR(255) NOT NULL,
    80                         username VARCHAR(255) NOT NULL UNIQUE,
    81                         phone VARCHAR(255) NOT NULL UNIQUE,
    82                         email VARCHAR(255) NOT NULL UNIQUE,
    83                         password_hash TEXT NOT NULL,
    84                         created_at TIMESTAMP NOT NULL,
    85                         status_id INT NOT NULL,
    86 
    87                         CONSTRAINT chk_admins_phone CHECK (phone ~ '^[0-9+]+$'),
    88                         CONSTRAINT chk_admins_email CHECK (email ~ '^[^@]+@[^@]+\.[^@]+$'),
    89 
    90                         CONSTRAINT FK_Admins_Status
    91                             FOREIGN KEY (status_id) REFERENCES Status(status_id)
    92                                 ON DELETE RESTRICT
    93                                 ON UPDATE CASCADE
     77    admins_id SERIAL PRIMARY KEY,
     78    name VARCHAR(255) NOT NULL,
     79    username VARCHAR(255) NOT NULL UNIQUE,
     80    phone VARCHAR(255) NOT NULL UNIQUE,
     81    email VARCHAR(255) NOT NULL UNIQUE,
     82    password_hash TEXT NOT NULL,
     83    created_at TIMESTAMP NOT NULL,
     84    status_id INT NOT NULL,
     85
     86    CONSTRAINT chk_admins_phone CHECK (phone ~ '^[0-9+]+$'),
     87    CONSTRAINT chk_admins_email CHECK (email ~ '^[^@]+@[^@]+\.[^@]+$'),
     88
     89    CONSTRAINT FK_Admins_Status
     90        FOREIGN KEY (status_id) REFERENCES Status(status_id)
     91            ON DELETE RESTRICT
     92            ON UPDATE CASCADE
    9493);
    9594
    9695CREATE TABLE Vehicle_types (
    97                                vehicle_type_id SERIAL PRIMARY KEY,
    98                                type_name VARCHAR(255) NOT NULL,
    99                                description VARCHAR(255) NOT NULL,
    100                                Vehicles_model_id INT NOT NULL,
    101 
    102                                CONSTRAINT FK_Vehicle_types_Model
    103                                    FOREIGN KEY (Vehicles_model_id)
    104                                        REFERENCES Vehicles_model(Vehicles_model_id)
    105                                        ON DELETE RESTRICT
    106                                        ON UPDATE CASCADE
     96    vehicle_type_id SERIAL PRIMARY KEY,
     97    type_name VARCHAR(255) NOT NULL,
     98    description VARCHAR(255) NOT NULL,
     99    Vehicles_model_id INT NOT NULL,
     100
     101    CONSTRAINT FK_Vehicle_types_Model
     102        FOREIGN KEY (Vehicles_model_id)
     103            REFERENCES Vehicles_model(Vehicles_model_id)
     104            ON DELETE RESTRICT
     105            ON UPDATE CASCADE
    107106);
    108107
    109108CREATE TABLE Vehicle_ownership (
    110                                    Vehicle_ownership_id SERIAL PRIMARY KEY,
    111                                    Plate VARCHAR(255) NOT NULL UNIQUE,
    112                                    Traffic_permit VARCHAR(255) NOT NULL UNIQUE,
    113                                    Color VARCHAR(255) NOT NULL,
    114                                    year INT NOT NULL,
    115                                    vehicle_type_id INT NOT NULL,
    116 
    117 
    118                                    CONSTRAINT chk_vehicle_year CHECK (year >= 1900),
    119 
    120                                    CONSTRAINT FK_Vehicle_ownership_Type
    121                                        FOREIGN KEY (vehicle_type_id)
    122                                            REFERENCES Vehicle_types(vehicle_type_id)
    123                                            ON DELETE RESTRICT
    124                                            ON UPDATE CASCADE
     109    Vehicle_ownership_id SERIAL PRIMARY KEY,
     110    Plate VARCHAR(255) NOT NULL UNIQUE,
     111    Traffic_permit VARCHAR(255) NOT NULL UNIQUE,
     112    Color VARCHAR(255) NOT NULL,
     113    year INT NOT NULL,
     114    vehicle_type_id INT NOT NULL,
     115
     116    CONSTRAINT chk_vehicle_year CHECK (year >= 1900),
     117
     118    CONSTRAINT FK_Vehicle_ownership_Type
     119        FOREIGN KEY (vehicle_type_id)
     120            REFERENCES Vehicle_types(vehicle_type_id)
     121            ON DELETE RESTRICT
     122            ON UPDATE CASCADE
    125123);
    126124
    127125CREATE TABLE Pricing_rules (
    128                                tariff_id SERIAL PRIMARY KEY,
    129                                base_price NUMERIC(10,2) NOT NULL,
    130                                price_per_km NUMERIC(10,2) NOT NULL,
    131                                vehicle_type_id INT NOT NULL,
    132 
    133                                CONSTRAINT chk_price CHECK (base_price >= 0 AND price_per_km >= 0),
    134 
    135                                CONSTRAINT FK_Pricing_rules_Vehicle_types
    136                                    FOREIGN KEY (vehicle_type_id)
    137                                        REFERENCES Vehicle_types(vehicle_type_id)
    138                                        ON DELETE RESTRICT
    139                                        ON UPDATE CASCADE
     126    tariff_id SERIAL PRIMARY KEY,
     127    base_price NUMERIC(10,2) NOT NULL,
     128    price_per_km NUMERIC(10,2) NOT NULL,
     129    vehicle_type_id INT NOT NULL,
     130
     131    CONSTRAINT chk_price CHECK (base_price >= 0 AND price_per_km >= 0),
     132
     133    CONSTRAINT FK_Pricing_rules_Vehicle_types
     134        FOREIGN KEY (vehicle_type_id)
     135            REFERENCES Vehicle_types(vehicle_type_id)
     136            ON DELETE RESTRICT
     137            ON UPDATE CASCADE
    140138);
    141139
    142140CREATE TABLE Drivers_Vehicle_ownership (
    143                                            driver_id INT NOT NULL,
    144                                            Vehicle_ownership_id INT NOT NULL,
    145 
    146                                            PRIMARY KEY (driver_id, Vehicle_ownership_id),
    147 
    148                                            CONSTRAINT FK_DVO_Drivers
    149                                                FOREIGN KEY (driver_id)
    150                                                    REFERENCES Drivers(driver_id)
    151                                                     ON DELETE CASCADE,
    152 
    153                                            CONSTRAINT FK_DVO_Vehicles
    154                                                FOREIGN KEY (Vehicle_ownership_id)
    155                                                    REFERENCES Vehicle_ownership(Vehicle_ownership_id)
    156                                                    ON DELETE CASCADE
     141    driver_id INT NOT NULL,
     142    Vehicle_ownership_id INT NOT NULL,
     143
     144    PRIMARY KEY (driver_id, Vehicle_ownership_id),
     145
     146    CONSTRAINT FK_DVO_Drivers
     147        FOREIGN KEY (driver_id)
     148            REFERENCES Drivers(driver_id)
     149            ON DELETE CASCADE,
     150
     151    CONSTRAINT FK_DVO_Vehicles
     152        FOREIGN KEY (Vehicle_ownership_id)
     153            REFERENCES Vehicle_ownership(Vehicle_ownership_id)
     154            ON DELETE CASCADE
    157155);
    158156
    159157CREATE TABLE Active_drivers (
    160                                 driver_id INT PRIMARY KEY,
    161                                 current_location_id INT NOT NULL,
    162                                 is_available BOOLEAN NOT NULL,
    163                                 working_start TIMESTAMP NOT NULL,
    164                                 working_end TIMESTAMP NOT NULL,
    165                                 vehicle_ownership_id INT NOT NULL,
    166 
    167                                 CONSTRAINT FK_Active_drivers_Drivers
    168                                     FOREIGN KEY (driver_id)
    169                                         REFERENCES Drivers(driver_id)
    170                                         ON DELETE CASCADE,
    171 
    172                                 CONSTRAINT FK_Active_drivers_Locations
    173                                     FOREIGN KEY (current_location_id)
    174                                         REFERENCES Locations(location_id)
    175                                         ON DELETE RESTRICT,
    176 
    177                                 CONSTRAINT FK_Active_drivers_vehicle_ownership_id
    178                                     FOREIGN KEY (vehicle_ownership_id)
    179                                         REFERENCES Vehicle_ownership(Vehicle_ownership_id)
    180                                         ON DELETE RESTRICT
     158    driver_id INT PRIMARY KEY,
     159    current_location_id INT NOT NULL,
     160    is_available BOOLEAN NOT NULL,
     161    working_start TIMESTAMP NOT NULL,
     162    working_end TIMESTAMP NOT NULL,
     163    vehicle_ownership_id INT NOT NULL,
     164
     165    CONSTRAINT FK_Active_drivers_Drivers
     166        FOREIGN KEY (driver_id)
     167            REFERENCES Drivers(driver_id)
     168            ON DELETE CASCADE,
     169
     170    CONSTRAINT FK_Active_drivers_Locations
     171        FOREIGN KEY (current_location_id)
     172            REFERENCES Locations(location_id)
     173            ON DELETE RESTRICT,
     174
     175    CONSTRAINT FK_Active_drivers_vehicle_ownership_id
     176        FOREIGN KEY (vehicle_ownership_id)
     177            REFERENCES Vehicle_ownership(Vehicle_ownership_id)
     178            ON DELETE RESTRICT
    181179);
    182180
    183181CREATE TABLE Rides (
    184                        ride_id SERIAL PRIMARY KEY,
    185                        user_id INT NOT NULL,
    186                        driver_id INT NOT NULL,
    187                        vehicle_ownership_id INT NOT NULL,
    188                        pickup_location_id INT NOT NULL,
    189                        dropoff_location_id INT NOT NULL,
    190                        status_id INT NOT NULL,
    191                        request_time TIMESTAMP NOT NULL,
    192                        pickup_time TIMESTAMP NOT NULL,
    193                        start_time TIMESTAMP NOT NULL,
    194                        end_time TIMESTAMP NOT NULL,
    195                        distance_km NUMERIC(6,2) NOT NULL,
    196                        final_price NUMERIC(10,2) NOT NULL,
    197                        discount_percentage NUMERIC(5,2) NOT NULL,
    198 
    199 
    200                        CONSTRAINT chk_distance CHECK (distance_km >= 0),
    201                        CONSTRAINT chk_discount CHECK (discount_percentage BETWEEN 0 AND 100),
    202 
    203                        CONSTRAINT FK_Rides_Users
    204                            FOREIGN KEY (user_id) REFERENCES Users(User_id) ON DELETE RESTRICT,
    205 
    206                        CONSTRAINT FK_Rides_vehicle_ownership_id
    207                            FOREIGN KEY (vehicle_ownership_id) REFERENCES Vehicle_ownership(Vehicle_ownership_id) ON DELETE RESTRICT,
    208 
    209                        CONSTRAINT FK_Rides_Drivers
    210                            FOREIGN KEY (driver_id) REFERENCES Drivers(driver_id) ON DELETE RESTRICT,
    211 
    212                        CONSTRAINT FK_Rides_Pickup_Location
    213                            FOREIGN KEY (pickup_location_id) REFERENCES Locations(location_id) ON DELETE RESTRICT,
    214 
    215                        CONSTRAINT FK_Rides_Dropoff_Location
    216                            FOREIGN KEY (dropoff_location_id) REFERENCES Locations(location_id) ON DELETE RESTRICT,
    217 
    218                        CONSTRAINT FK_Rides_Status
    219                            FOREIGN KEY (status_id) REFERENCES Status(status_id) ON DELETE RESTRICT
     182    ride_id SERIAL PRIMARY KEY,
     183    user_id INT NOT NULL,
     184    driver_id INT NOT NULL,
     185    vehicle_ownership_id INT NOT NULL,
     186    pickup_location_id INT NOT NULL,
     187    dropoff_location_id INT NOT NULL,
     188    status_id INT NOT NULL,
     189    request_time TIMESTAMP NOT NULL,
     190    pickup_time TIMESTAMP NOT NULL,
     191    start_time TIMESTAMP NOT NULL,
     192    end_time TIMESTAMP NOT NULL,
     193    distance_km NUMERIC(6,2) NOT NULL,
     194    final_price NUMERIC(10,2) NOT NULL,
     195    discount_percentage NUMERIC(5,2) NOT NULL,
     196
     197    CONSTRAINT chk_distance CHECK (distance_km >= 0),
     198    CONSTRAINT chk_discount CHECK (discount_percentage BETWEEN 0 AND 100),
     199
     200    CONSTRAINT FK_Rides_Users
     201        FOREIGN KEY (user_id) REFERENCES Users(User_id) ON DELETE RESTRICT,
     202
     203    CONSTRAINT FK_Rides_vehicle_ownership_id
     204        FOREIGN KEY (vehicle_ownership_id) REFERENCES Vehicle_ownership(Vehicle_ownership_id) ON DELETE RESTRICT,
     205
     206    CONSTRAINT FK_Rides_Drivers
     207        FOREIGN KEY (driver_id) REFERENCES Drivers(driver_id) ON DELETE RESTRICT,
     208
     209    CONSTRAINT FK_Rides_Pickup_Location
     210        FOREIGN KEY (pickup_location_id) REFERENCES Locations(location_id) ON DELETE RESTRICT,
     211
     212    CONSTRAINT FK_Rides_Dropoff_Location
     213        FOREIGN KEY (dropoff_location_id) REFERENCES Locations(location_id) ON DELETE RESTRICT,
     214
     215    CONSTRAINT FK_Rides_Status
     216        FOREIGN KEY (status_id) REFERENCES Status(status_id) ON DELETE RESTRICT
    220217);
    221218
    222219CREATE TABLE Payment_methods(
    223                                 payment_method_id SERIAL PRIMARY KEY,
    224                                 payment_tip  VARCHAR(255) NOT NULL
     220    payment_method_id SERIAL PRIMARY KEY,
     221    payment_tip VARCHAR(255) NOT NULL
    225222);
    226223
    227224CREATE TABLE Payments (
    228                           payment_id SERIAL PRIMARY KEY,
    229                           amount NUMERIC(10,2) NOT NULL,
    230                           payment_method_id INT NOT NULL,
    231                           payment_time TIMESTAMP NOT NULL,
    232                           ride_id INT NOT NULL,
    233                           status_id INT NOT NULL,
    234 
    235                           CONSTRAINT chk_amount CHECK (amount >= 0),
    236 
    237                           CONSTRAINT FK_Payments_Rides
    238                               FOREIGN KEY (ride_id) REFERENCES Rides(ride_id) ON DELETE CASCADE,
    239 
    240                           CONSTRAINT FK_Payments_Status
    241                               FOREIGN KEY (status_id) REFERENCES Status(status_id) ON DELETE RESTRICT,
    242 
    243                           CONSTRAINT FK_Payments_Method
    244                               FOREIGN KEY (payment_method_id) REFERENCES Payment_methods(payment_method_id) ON DELETE RESTRICT
     225    payment_id SERIAL PRIMARY KEY,
     226    amount NUMERIC(10,2) NOT NULL,
     227    payment_method_id INT NOT NULL,
     228    payment_time TIMESTAMP NOT NULL,
     229    ride_id INT NOT NULL,
     230    status_id INT NOT NULL,
     231
     232    CONSTRAINT chk_amount CHECK (amount >= 0),
     233
     234    CONSTRAINT FK_Payments_Rides
     235        FOREIGN KEY (ride_id) REFERENCES Rides(ride_id) ON DELETE CASCADE,
     236
     237    CONSTRAINT FK_Payments_Status
     238        FOREIGN KEY (status_id) REFERENCES Status(status_id) ON DELETE RESTRICT,
     239
     240    CONSTRAINT FK_Payments_Method
     241        FOREIGN KEY (payment_method_id) REFERENCES Payment_methods(payment_method_id) ON DELETE RESTRICT
    245242);
    246243
    247244CREATE TABLE Ratings (
    248                          rating_id SERIAL PRIMARY KEY,
    249                          score INT NOT NULL,
    250                          comment VARCHAR(255),
    251                          created_at TIMESTAMP NOT NULL,
    252                          ride_id INT NOT NULL,
    253                          User_id INT NOT NULL,
    254                          driver_id INT NOT NULL,
    255 
    256                          CONSTRAINT chk_score CHECK (score BETWEEN 1 AND 5),
    257 
    258                          CONSTRAINT FK_Ratings_Rides
    259                              FOREIGN KEY (ride_id) REFERENCES Rides(ride_id) ON DELETE CASCADE,
    260 
    261                          CONSTRAINT FK_Ratings_Users
    262                              FOREIGN KEY (User_id) REFERENCES Users(User_id) ON DELETE CASCADE,
    263 
    264                          CONSTRAINT FK_Ratings_Drivers
    265                              FOREIGN KEY (driver_id) REFERENCES Drivers(driver_id) ON DELETE CASCADE
     245    rating_id SERIAL PRIMARY KEY,
     246    score INT NOT NULL,
     247    comment VARCHAR(255),
     248    created_at TIMESTAMP NOT NULL,
     249    ride_id INT NOT NULL,
     250    User_id INT NOT NULL,
     251    driver_id INT NOT NULL,
     252
     253    CONSTRAINT chk_score CHECK (score BETWEEN 1 AND 5),
     254
     255    CONSTRAINT FK_Ratings_Rides
     256        FOREIGN KEY (ride_id) REFERENCES Rides(ride_id) ON DELETE CASCADE,
     257
     258    CONSTRAINT FK_Ratings_Users
     259        FOREIGN KEY (User_id) REFERENCES Users(User_id) ON DELETE CASCADE,
     260
     261    CONSTRAINT FK_Ratings_Drivers
     262        FOREIGN KEY (driver_id) REFERENCES Drivers(driver_id) ON DELETE CASCADE
    266263);
    267264
    268265CREATE TABLE Cancellations (
    269                                cancellation_id SERIAL PRIMARY KEY,
    270                                cancelled_by_type VARCHAR(255) NOT NULL,
    271                                cancelled_by_id INT NOT NULL,
    272                                reason VARCHAR(255) NOT NULL,
    273                                cancellation_fee NUMERIC(10,2) NOT NULL,
    274                                created_at TIMESTAMP NOT NULL,
    275                                ride_id INT NOT NULL,
    276 
    277                                CONSTRAINT chk_fee CHECK (cancellation_fee >= 0),
    278                                CONSTRAINT chk_cancelled_by_type CHECK (cancelled_by_type IN ('USER', 'DRIVER', 'ADMIN')),
    279 
    280                                CONSTRAINT FK_Cancellations_Rides
    281                                    FOREIGN KEY (ride_id) REFERENCES Rides(ride_id) ON DELETE CASCADE
     266    cancellation_id SERIAL PRIMARY KEY,
     267    cancelled_by_type VARCHAR(255) NOT NULL,
     268    cancelled_by_id INT NOT NULL,
     269    reason VARCHAR(255) NOT NULL,
     270    cancellation_fee NUMERIC(10,2) NOT NULL,
     271    created_at TIMESTAMP NOT NULL,
     272    ride_id INT NOT NULL,
     273
     274    CONSTRAINT chk_fee CHECK (cancellation_fee >= 0),
     275    CONSTRAINT chk_cancelled_by_type CHECK (cancelled_by_type IN ('USER', 'DRIVER', 'ADMIN')),
     276
     277    CONSTRAINT FK_Cancellations_Rides
     278        FOREIGN KEY (ride_id) REFERENCES Rides(ride_id) ON DELETE CASCADE
    282279);
    283280
    284281CREATE TABLE Messages(
    285                          message_id SERIAL PRIMARY KEY,
    286                          message_text VARCHAR(255) NOT NULL
    287 
     282    message_id SERIAL PRIMARY KEY,
     283    message_text VARCHAR(255) NOT NULL
    288284);
    289285
    290286CREATE TABLE Notifications (
    291                                notification_id SERIAL PRIMARY KEY,
    292                                message_id INT NOT NULL,
    293                                sent_time TIMESTAMP NOT NULL,
    294                                User_id INT NOT NULL,
    295                                ride_id INT NOT NULL,
    296                                status_id INT NOT NULL,
    297 
    298                                CONSTRAINT FK_Notifications_Users
    299                                    FOREIGN KEY (User_id) REFERENCES Users(User_id) ON DELETE CASCADE,
    300 
    301                                CONSTRAINT FK_Notifications_Rides
    302                     
    303                                FOREIGN KEY (ride_id) REFERENCES Rides(ride_id) ON DELETE CASCADE,
    304 
    305                                CONSTRAINT FK_Notifications_Status
    306                                    FOREIGN KEY (status_id) REFERENCES Status(status_id) ON DELETE RESTRICT,
    307 
    308                                CONSTRAINT FK_Notifications_Messages
    309                                     FOREIGN KEY (message_id) REFERENCES Messages(message_id) ON DELETE CASCADE
    310 );
    311 ```
     287    notification_id SERIAL PRIMARY KEY,
     288    message_id INT NOT NULL,
     289    sent_time TIMESTAMP NOT NULL,
     290    User_id INT NOT NULL,
     291    ride_id INT NOT NULL,
     292    status_id INT NOT NULL,
     293
     294    CONSTRAINT FK_Notifications_Users
     295        FOREIGN KEY (User_id) REFERENCES Users(User_id) ON DELETE CASCADE,
     296
     297    CONSTRAINT FK_Notifications_Rides
     298        FOREIGN KEY (ride_id) REFERENCES Rides(ride_id) ON DELETE CASCADE,
     299
     300    CONSTRAINT FK_Notifications_Status
     301        FOREIGN KEY (status_id) REFERENCES Status(status_id) ON DELETE RESTRICT,
     302
     303    CONSTRAINT FK_Notifications_Messages
     304        FOREIGN KEY (message_id) REFERENCES Messages(message_id) ON DELETE CASCADE
     305);
    312306
    313307=== DML Имплементација ===
    314 
    315308DML скриптите се користат за внесување, генерирање и управување со податоците во базата на податоци. Во овој проект, преку DML наредби се пополнуваат табелите со иницијални и тест податоци потребни за функционирање и симулација на ride-sharing системот.
    316309
     
    327320batch обработка и оптимизација за работа со милионски datasets
    328321
    329 користење на PostgreSQL DO $$ блокови и procedural логика
    330 
    331 Со овие DML скрипти се обезбедува реалистичен dataset кој овозможува тестирање, анализа и евалуација на перформансите на системот.
    332 
    333 === DML Скрипти ===
    334 ```
     322користе
     323
     324
    335325INSERT INTO Status (status_tip, status_text) VALUES
    336                                                  ('driver', 'active'),
    337                                                  ('driver', 'inactive');
     326    ('driver', 'active'),
     327    ('driver', 'inactive');
    338328INSERT INTO Status (status_tip, status_text) VALUES
    339                                                  ('user', 'active'),
    340                                                  ('user', 'inactive'),
    341                                                  ('user', 'blocked'),
    342                                                  ('user', 'deleted');
     329    ('user', 'active'),
     330    ('user', 'inactive'),
     331    ('user', 'blocked'),
     332    ('user', 'deleted');
    343333INSERT INTO Status (status_tip, status_text) VALUES
    344                                                  ('admin', 'active'),
    345                                                  ('admin', 'inactive'),
    346                                                  ('admin', 'blocked');
     334    ('admin', 'active'),
     335    ('admin', 'inactive'),
     336    ('admin', 'blocked');
    347337INSERT INTO Status (status_tip, status_text) VALUES
    348                                                  ('ride', 'requested'),
    349                                                  ('ride', 'accepted'),
    350                                                  ('ride', 'in_progress'),
    351                                                  ('ride', 'completed'),
    352                                                  ('ride', 'cancelled');
     338    ('ride', 'requested'),
     339    ('ride', 'accepted'),
     340    ('ride', 'in_progress'),
     341    ('ride', 'completed'),
     342    ('ride', 'cancelled');
    353343INSERT INTO Status (status_tip, status_text) VALUES
    354                                                  ('payment', 'pending'),
    355                                                  ('payment', 'completed'),
    356                                                  ('payment', 'failed'),
    357                                                  ('payment', 'refunded');
     344    ('payment', 'pending'),
     345    ('payment', 'completed'),
     346    ('payment', 'failed'),
     347    ('payment', 'refunded');
    358348
    359349INSERT INTO Payment_methods (payment_tip) VALUES
    360                                               ('CASH'),
    361                                               ('CARD');                                                
     350    ('CASH'),
     351    ('CARD');                                             
    362352
    363353INSERT INTO Messages (message_text) VALUES
    364                                         ('Vaseto baranje e uspesno isprateno'),
    365                                         ('Vozacot go prifati vaseto baranje'),
    366                                         ('Vozacot go odbi vaseto baranje'),
    367                                         ('Vozacot pristigna na lokacijata za podiganje'),
    368                                         ('Vozenjeto e otkazano od strana na vozacot'),
    369                                         ('Vozenjeto e otkazano od vasa strana'),
    370                                         ('Plakjanjeto e uspesno'),
    371                                         ('Plakjanjeto ne uspea'),
    372                                         ('Nemate dostapni vozaci vo momentot');  
    373                                         
     354    ('Vaseto baranje e uspesno isprateno'),
     355    ('Vozacot go prifati vaseto baranje'),
     356    ('Vozacot go odbi vaseto baranje'),
     357    ('Vozacot pristigna na lokacijata za podiganje'),
     358    ('Vozenjeto e otkazano od strana na vozacot'),
     359    ('Vozenjeto e otkazano od vasa strana'),
     360    ('Plakjanjeto e uspesno'),
     361    ('Plakjanjeto ne uspea'),
     362    ('Nemate dostapni vozaci vo momentot'); 
     363                                       
    374364INSERT INTO Vehicles_model (Model) VALUES
    375                                        ('Volkswagen'),
    376                                        ('Skoda'),
    377                                        ('Toyota'),
    378                                        ('Opel'),
    379                                        ('Mercedes-Benz'),
    380                                        ('BMW'),
    381                                        ('Audi'),
    382                                        ('Hyundai'),
    383                                        ('Kia'),
    384                                        ('Renault');    
    385                                        
     365    ('Volkswagen'),
     366    ('Skoda'),
     367    ('Toyota'),
     368    ('Opel'),
     369    ('Mercedes-Benz'),
     370    ('BMW'),
     371    ('Audi'),
     372    ('Hyundai'),
     373    ('Kia'),
     374    ('Renault');   
     375                                       
    386376INSERT INTO Vehicle_types (type_name, description, Vehicles_model_id)
    387377SELECT
    388     m.model_name,
    389     CASE
    390         WHEN m.model_name IN ('Golf','Octavia','Corolla','Astra','Polo','Fabia','Yaris','Corsa','Elantra','Clio',
    391                               'i30','Rio','Megane','Passat','Superb','Camry','Insignia','Tucson','Ceed','Captur')
    392             THEN 'Economy class'
    393         ELSE 'Luxury class'
    394         END as description,
    395     m.brand_id
     378    m.model_name,
     379    CASE
     380        WHEN m.model_name IN ('Golf','Octavia','Corolla','Astra','Polo','Fabia','Yaris','Corsa','Elantra','Clio',
     381                              'i30','Rio','Megane','Passat','Superb','Camry','Insignia','Tucson','Ceed','Captur')
     382            THEN 'Economy class'
     383        ELSE 'Luxury class'
     384        END as description,
     385    m.brand_id
    396386FROM (
    397          SELECT vm.Vehicles_model_id as brand_id, unnest(models) as model_name
    398          FROM Vehicles_model vm
    399                   JOIN (VALUES
    400                             ('Volkswagen', ARRAY['Golf','Passat','Tiguan','Polo','Arteon']),
    401                             ('Skoda',      ARRAY['Octavia','Superb','Kodiaq','Fabia','Karoq']),
    402                             ('Toyota',     ARRAY['Corolla','Yaris','RAV4','Camry','C-HR']),
    403                             ('Opel',       ARRAY['Astra','Insignia','Corsa','Mokka','Grandland']),
    404                             ('Mercedes-Benz', ARRAY['E-Class','C-Class','S-Class','GLE','CLA']),
    405                             ('BMW',        ARRAY['3 Series','5 Series','X5','X3','1 Series']),
    406                             ('Audi',       ARRAY['A4','A6','Q5','A3','Q7']),
    407                             ('Hyundai',    ARRAY['Elantra','Tucson','Santa Fe','i30','Kona']),
    408                             ('Kia',        ARRAY['Sportage','Ceed','Rio','Sorento','Niro']),
    409                             ('Renault',    ARRAY['Clio','Megane','Captur','Kadjar','Talisman'])
    410          ) AS t(brand, models) ON vm.Model = t.brand
    411      ) m;
    412     
     387         SELECT vm.Vehicles_model_id as brand_id, unnest(models) as model_name
     388         FROM Vehicles_model vm
     389                  JOIN (VALUES
     390                            ('Volkswagen', ARRAY['Golf','Passat','Tiguan','Polo','Arteon']),
     391                            ('Skoda',      ARRAY['Octavia','Superb','Kodiaq','Fabia','Karoq']),
     392                            ('Toyota',     ARRAY['Corolla','Yaris','RAV4','Camry','C-HR']),
     393                            ('Opel',       ARRAY['Astra','Insignia','Corsa','Mokka','Grandland']),
     394                            ('Mercedes-Benz', ARRAY['E-Class','C-Class','S-Class','GLE','CLA']),
     395                            ('BMW',        ARRAY['3 Series','5 Series','X5','X3','1 Series']),
     396                            ('Audi',       ARRAY['A4','A6','Q5','A3','Q7']),
     397                            ('Hyundai',    ARRAY['Elantra','Tucson','Santa Fe','i30','Kona']),
     398                            ('Kia',        ARRAY['Sportage','Ceed','Rio','Sorento','Niro']),
     399                            ('Renault',    ARRAY['Clio','Megane','Captur','Kadjar','Talisman'])
     400         ) AS t(brand, models) ON vm.Model = t.brand
     401     ) m;
     402   
    413403INSERT INTO Pricing_rules (base_price, price_per_km, vehicle_type_id)
    414404SELECT
    415     CASE
    416         WHEN description = 'Economy class' THEN 80.00
    417         ELSE 100.00
    418         END as base_price,
    419     CASE
    420         WHEN description = 'Economy class' THEN 40.00
    421         ELSE 60.00
    422         END as price_per_km,
    423     vehicle_type_id
    424 FROM Vehicle_types;    
     405    CASE
     406        WHEN description = 'Economy class' THEN 80.00
     407        ELSE 100.00
     408        END as base_price,
     409    CASE
     410        WHEN description = 'Economy class' THEN 40.00
     411        ELSE 60.00
     412        END as price_per_km,
     413    vehicle_type_id
     414FROM Vehicle_types;   
    425415
    426416INSERT INTO Locations (latitude, longitude, grad, naselba, ulica, broj, created_at)
    427417WITH street_data AS (
    428     SELECT * FROM (VALUES
    429                        ('Centar', 42.1322, 21.7144, ARRAY[
    430                            '11 Oktomvri', 'Goce Delchev', 'Tane Georgiev', 'Gorce Petrov', 'Plostad Marsal Tito',
    431                            'Done Bozhinov', 'Ljubo Atanasov', 'Ivo Lola Ribar', 'Leninova', 'Narodna Revolucija',
    432                            'Svetozar Markovic', 'Krste Misirkov', 'Jane Sandanski', 'Dragan Stoparevic', 'Bratstvo Edinstvo',
    433                            'Marsal Tito', 'JNA', 'Stiv Naumov', 'Guro Pucar Stari', 'Hristijan Karpos'
    434                            ]),
    435                        ('Zelen Rid', 42.1400, 21.7000, ARRAY[
    436                            'Nikola Tesla', 'Zheleznichka', 'Vidoe Smilevski Bato', 'Vasil Glavinov', 'Sremska',
    437                            'Kozjak', 'Osogovska', 'Shar Planina', 'Belasica', 'Ruen',
    438                            'Prilepska', 'Bitolska', 'Ohridska', 'Strumicka', 'Vardar',
    439                            'Pelister', 'Skopska', 'Tetovska', 'Gevgeliska', 'Veleska'
    440                            ]),
    441                        ('Goce Delchev', 42.1250, 21.7250, ARRAY[
    442                            'Treta Makedonska Udarna Brigada', 'Vera Kotorka', 'Boro Mikic', 'Filip Vtori', 'Srbo Tomovik',
    443                            'Zikica Jovanovic Spanac', 'Boro Menkov', 'Milan Zecar', 'Dositej Obradovic', 'Kuzman Josifovski Pitu',
    444                            'Tomaki Dimitrovski', 'Todor Velkov', 'Vasko Karangelevski', 'Niksicka', 'Pero Nakov',
    445                            'Bajram Shabani', 'Mite Bogoevski', 'Slavko Janevski', 'Gjorce Petrov', 'Kiro Fetak'
    446                            ]),
    447                        ('Pero Chicho', 42.1150, 21.7300, ARRAY[
    448                            'Pero Chicho', '11 Noemvri', 'Boro Mendkov', 'Josip Pancic', 'Banatska',
    449                            'Moravska', 'Drinska', 'Sredorek', 'Vojvodina', 'Sumadinska',
    450                            'Toplicki Odred', 'Zajecarska', 'Niska', 'Vranjska', 'Leskovacka',
    451                            'Sremska', 'Prizrenska', 'Dakovicka', 'Pecka', 'Kosovska'
    452                            ]),
    453                        ('Karposh', 42.1200, 21.7500, ARRAY[
    454                            'Oktomvriska Revolucija', 'Srecko Puzalka', 'Mito Hadzivasilev Jasmin', 'Sava Kovacevic', 'Karposova',
    455                            'Metodija Andonov Cento', 'ASNOM', 'Dame Gruev', 'Pitu Guli', 'Partizanska',
    456                            'Kiro Burnaz', 'Pere Tosev', 'Gjorce Petrov', 'Hristijan Todorovski', 'Miroslav Krleza',
    457                            'Blagoja Stevkovski', 'Kosta Racin', 'Koco Racin', 'Mirce Acev', 'Vasil Antevski'
    458                            ]),
    459                        ('Bedinje', 42.1500, 21.7100, ARRAY[
    460                            'Srbo Tomovikj', 'Zhivko Tomovski', 'Guro Djakovic', 'Karaorman', 'Njegoseva',
    461                            'Ivan Milutinovic', 'Mojsa Pijade', 'Zheleznichka', 'Revolucionerna', 'Gjorce Petrov',
    462                            'Cede Filipovski', 'Bratstvo', 'Edinstvo', 'Prvomajska', 'Sloboda',
    463                            'Proleterska', 'Makedonska', 'Ilindenska', 'Vidoe Smilevski', 'Josip Pancic'
    464                            ]),
    465                        ('Ajducka Cheshma', 42.1480, 21.6950, ARRAY[
    466                            'Bajram Shabani', 'Prilepska', 'Blagoja Stevkovski', 'Romanovska', 'Kumanovska',
    467                            'Debarska', 'Krusevska', 'Dojranska', 'Prespanska', 'Gevgeliska',
    468                            'Negotinska', 'Kavadarska', 'Radoviska', 'Berovska', 'Delcevska',
    469                            'Vinicka', 'Kratovska', 'Zletovska', 'Probistipska', 'Svetinikolska'
    470                            ])
    471                   ) AS t(naselba, lat_base, lon_base, ulici)
     418    SELECT * FROM (VALUES
     419                       ('Centar', 42.1322, 21.7144, ARRAY[
     420                           '11 Oktomvri', 'Goce Delchev', 'Tane Georgiev', 'Gorce Petrov', 'Plostad Marsal Tito',
     421                           'Done Bozhinov', 'Ljubo Atanasov', 'Ivo Lola Ribar', 'Leninova', 'Narodna Revolucija',
     422                           'Svetozar Markovic', 'Krste Misirkov', 'Jane Sandanski', 'Dragan Stoparevic', 'Bratstvo Edinstvo',
     423                           'Marsal Tito', 'JNA', 'Stiv Naumov', 'Guro Pucar Stari', 'Hristijan Karpos'
     424                           ]),
     425                       ('Zelen Rid', 42.1400, 21.7000, ARRAY[
     426                           'Nikola Tesla', 'Zheleznichka', 'Vidoe Smilevski Bato', 'Vasil Glavinov', 'Sremska',
     427                           'Kozjak', 'Osogovska', 'Shar Planina', 'Belasica', 'Ruen',
     428                           'Prilepska', 'Bitolska', 'Ohridska', 'Strumicka', 'Vardar',
     429                           'Pelister', 'Skopska', 'Tetovska', 'Gevgeliska', 'Veleska'
     430                           ]),
     431                       ('Goce Delchev', 42.1250, 21.7250, ARRAY[
     432                           'Treta Makedonska Udarna Brigada', 'Vera Kotorka', 'Boro Mikic', 'Filip Vtori', 'Srbo Tomovik',
     433                           'Zikica Jovanovic Spanac', 'Boro Menkov', 'Milan Zecar', 'Dositej Obradovic', 'Kuzman Josifovski Pitu',
     434                           'Tomaki Dimitrovski', 'Todor Velkov', 'Vasko Karangelevski', 'Niksicka', 'Pero Nakov',
     435                           'Bajram Shabani', 'Mite Bogoevski', 'Slavko Janevski', 'Gjorce Petrov', 'Kiro Fetak'
     436                           ]),
     437                       ('Pero Chicho', 42.1150, 21.7300, ARRAY[
     438                           'Pero Chicho', '11 Noemvri', 'Boro Mendkov', 'Josip Pancic', 'Banatska',
     439                           'Moravska', 'Drinska', 'Sredorek', 'Vojvodina', 'Sumadinska',
     440                           'Toplicki Odred', 'Zajecarska', 'Niska', 'Vranjska', 'Leskovacka',
     441                           'Sremska', 'Prizrenska', 'Dakovicka', 'Pecka', 'Kosovska'
     442                           ]),
     443                       ('Karposh', 42.1200, 21.7500, ARRAY[
     444                           'Oktomvriska Revolucija', 'Srecko Puzalka', 'Mito Hadzivasilev Jasmin', 'Sava Kovacevic', 'Karposova',
     445                           'Metodija Andonov Cento', 'ASNOM', 'Dame Gruev', 'Pitu Guli', 'Partizanska',
     446                           'Kiro Burnaz', 'Pere Tosev', 'Gjorce Petrov', 'Hristijan Todorovski', 'Miroslav Krleza',
     447                           'Blagoja Stevkovski', 'Kosta Racin', 'Koco Racin', 'Mirce Acev', 'Vasil Antevski'
     448                           ]),
     449                       ('Bedinje', 42.1500, 21.7100, ARRAY[
     450                           'Srbo Tomovikj', 'Zhivko Tomovski', 'Guro Djakovic', 'Karaorman', 'Njegoseva',
     451                           'Ivan Milutinovic', 'Mojsa Pijade', 'Zheleznichka', 'Revolucionerna', 'Gjorce Petrov',
     452                           'Cede Filipovski', 'Bratstvo', 'Edinstvo', 'Prvomajska', 'Sloboda',
     453                           'Proleterska', 'Makedonska', 'Ilindenska', 'Vidoe Smilevski', 'Josip Pancic'
     454                           ]),
     455                       ('Ajducka Cheshma', 42.1480, 21.6950, ARRAY[
     456                           'Bajram Shabani', 'Prilepska', 'Blagoja Stevkovski', 'Romanovska', 'Kumanovska',
     457                           'Debarska', 'Krusevska', 'Dojranska', 'Prespanska', 'Gevgeliska',
     458                           'Negotinska', 'Kavadarska', 'Radoviska', 'Berovska', 'Delcevska',
     459                           'Vinicka', 'Kratovska', 'Zletovska', 'Probistipska', 'Svetinikolska'
     460                           ])
     461                  ) AS t(naselba, lat_base, lon_base, ulici)
    472462),
    473      expanded AS (
    474          SELECT
    475              naselba,
    476              lat_base,
    477              lon_base,
    478              unnest(ulici) as ulica
    479          FROM street_data
    480      ),
    481      numbered AS (
    482          SELECT
    483              naselba,
    484              lat_base,
    485              lon_base,
    486              ulica,
    487              row_number() OVER (PARTITION BY naselba ORDER BY ulica) as street_num
    488          FROM expanded
    489      )
     463     expanded AS (
     464         SELECT
     465             naselba,
     466             lat_base,
     467             lon_base,
     468             unnest(ulici) as ulica
     469         FROM street_data
     470     ),
     471     numbered AS (
     472         SELECT
     473             naselba,
     474             lat_base,
     475             lon_base,
     476             ulica,
     477             row_number() OVER (PARTITION BY naselba ORDER BY ulica) as street_num
     478         FROM expanded
     479     )
    490480SELECT
    491     (lat_base
    492         + (street_num * 0.0008)
    493         + (n.num * 0.000045)
    494         + (random() * 0.00005 - 0.000025)
    495         )::NUMERIC(9,6)                                         AS latitude,
    496 
    497     (lon_base
    498         + (street_num * 0.0010)
    499         + (n.num * 0.000060)
    500         + (random() * 0.00005 - 0.000025)
    501         )::NUMERIC(9,6)                                         AS longitude,
    502 
    503     'Kumanovo'                                              AS grad,
    504     nd.naselba                                              AS naselba,
    505     nd.ulica                                                AS ulica,
    506     n.num::VARCHAR                                          AS број,
    507 
    508     (NOW() - interval '5 years' - (random() * interval '365 days'))::TIMESTAMP AS created_at
     481    (lat_base
     482        + (street_num * 0.0008)
     483        + (n.num * 0.000045)
     484        + (random() * 0.00005 - 0.000025)
     485        )::NUMERIC(9,6)                                         AS latitude,
     486
     487    (lon_base
     488        + (street_num * 0.0010)
     489        + (n.num * 0.000060)
     490        + (random() * 0.00005 - 0.000025)
     491        )::NUMERIC(9,6)                                         AS longitude,
     492
     493    'Kumanovo'                                              AS grad,
     494    nd.naselba                                              AS naselba,
     495    nd.ulica                                                AS ulica,
     496    n.num::VARCHAR                                          AS broj,
     497
     498    (NOW() - interval '5 years' - (random() * interval '365 days'))::TIMESTAMP AS created_at
    509499
    510500FROM numbered nd
    511          CROSS JOIN generate_series(1, 100) AS n(num);
    512         
    513         
     501         CROSS JOIN generate_series(1, 100) AS n(num);
     502       
     503       
    514504INSERT INTO Users (
    515     name,
    516     username,
    517     phone,
    518     email,
    519     password_hash,
    520     created_at,
    521     status_id
     505    name,
     506    username,
     507    phone,
     508    email,
     509    password_hash,
     510    created_at,
     511    status_id
    522512)
    523513WITH data_pools AS (
    524     SELECT
    525         ARRAY['Marija','Ana','Ivana','Elena','Sara','Katerina','Jana','Mila','Teodora','Kristina','Sofija','Jovana','Tamara','Simona','Biljana','Vesna','Diana','Lidija','Monika','Angela','Ema','Tijana','Marina','Sonja','Nina','Anita','Valentina','Dragana','Ivona','Aleksandra','Natasha','Katarina','Emilija','Andrea','Gabriela','Tea','Danica','Zvezdana','Slobodanka','Gordana','Zorica','Ljubica','Rada','Mirjana','Despina','Kalina','Dafina','Hristina','Anastasija','Snezhana','Zlatka','Stojanka','Stana','Milka','Roksana','Romina','Karolina','Alina','Elina','Selina','Adelina','Darija','Dorotea','Nela','Neda','Zana','Hana','Ines','Iva','Irina','Arina','Lara','Tara','Dara','Kira','Lila','Tina','Jasmina','Bilja','Vanja','Maja','Bojana','Milena','Stefanija','Viktorija','Tatjana','Slavica','Ruzica'] AS f_names,
    526         ARRAY['Petar','Marko','Nikola','Stefan','Daniel','Goran','Bojan','Andrej','Filip','Viktor','Aleksandar','Dejan','Zoran','Ilija','Dimitar','Kiril','Hristijan','Vladimir','Vasko','Riste','Martin','Igor','Kristijan','Nenad','Damjan','Darko','Oliver','Simeon','Luka','Emil','Alen','Stojan','Metodija','Vlatko','Boris','Davor','Radoslav','Kosta','Mladen','Mile','Petre','Gjorgi','Trajan','Jovan','Ivan','Spas','Sasho','Zlatko','Bojcho','Risto','Bogdan','Tome','Kole','Vangel','Naum','Gligor','Stanko','Rade','Lazo','Arsen','Milko','Pavle','Dragan','Zdravko','Ilko','Vuk','Dame','Gorancho','Stevo','Miro'] AS m_names,
    527         ARRAY['Arsova','Dimitrova','Stojanova','Petrovska','Ilievska','Trajkova','Georgieva','Kostova','Maneva','Ristova','Popova','Jovanova','Nikolova','Mitrevska','Ivanova','Sokolova','Markova','Spasova','Angelova','Vasilevska','Pavlova','Gruevska','Nikolovska','Filipova','Stefanova','Andonova','Zafirova','Koleva','Stamenova','Bojkova','Todorova','Petkova','Hristova','Kitanova','Ilieva','Ruseva','Dimovska','Miloshevska','Petreska','Arnaudova','Georgievska','Markoska','Velkova','Stojkovska','Kirovska','Zlateva','Milevska','Naceva','Spiridonova','Lazarevska','Doneva','Atanasova','Bogdanova','Simeonova','Rangelova','Gligorova','Tasevska','Pancheva','Jankova','Bogoeva'] AS f_surnames,
    528         ARRAY['Arsov','Dimitrov','Stojanov','Petrovski','Iliev','Trajkov','Georgiev','Kostov','Manev','Ristov','Popov','Jovanov','Nikolov','Mitrev','Ivanov','Sokolov','Markov','Spasov','Angelov','Vasilev','Pavlov','Gruev','Nikolovski','Filipov','Stefanov','Andonov','Zafirov','Kolev','Stamenov','Bojkov','Todorov','Petkov','Hristov','Kitanov','Rusev','Dimovski','Miloshevski','Petreski','Arnaudov','Georgievski','Markoski','Velkov','Stojkovski','Kirovski','Zlatev','Milevski','Nacev','Spiridonov','Lazarevski','Donev','Atanasov','Bogdanov','Simeonov','Rangelov','Gligorov','Tasev','Panchev','Jankov','Bogoev','Karov','Trifunov','Gavrilov','Savov','Ilkov','Vukov','Zdravkov','Stojanovski','Danev'] AS m_surnames
     514    SELECT
     515        ARRAY['Marija','Ana','Ivana','Elena','Sara','Katerina','Jana','Mila','Teodora','Kristina','Sofija','Jovana','Tamara','Simona','Biljana','Vesna','Diana','Lidija','Monika','Angela','Ema','Tijana','Marina','Sonja','Nina','Anita','Valentina','Dragana','Ivona','Aleksandra','Natasha','Katarina','Emilija','Andrea','Gabriela','Tea','Danica','Zvezdana','Slobodanka','Gordana','Zorica','Ljubica','Rada','Mirjana','Despina','Kalina','Dafina','Hristina','Anastasija','Snezhana','Zlatka','Stojanka','Stana','Milka','Roksana','Romina','Karolina','Alina','Elina','Selina','Adelina','Darija','Dorotea','Nela','Neda','Zana','Hana','Ines','Iva','Irina','Arina','Lara','Tara','Dara','Kira','Lila','Tina','Jasmina','Bilja','Vanja','Maja','Bojana','Milena','Stefanija','Viktorija','Tatjana','Slavica','Ruzica'] AS f_names,
     516        ARRAY['Petar','Marko','Nikola','Stefan','Daniel','Goran','Bojan','Andrej','Filip','Viktor','Aleksandar','Dejan','Zoran','Ilija','Dimitar','Kiril','Hristijan','Vladimir','Vasko','Riste','Martin','Igor','Kristijan','Nenad','Damjan','Darko','Oliver','Simeon','Luka','Emil','Alen','Stojan','Metodija','Vlatko','Boris','Davor','Radoslav','Kosta','Mladen','Mile','Petre','Gjorgi','Trajan','Jovan','Ivan','Spas','Sasho','Zlatko','Bojcho','Risto','Bogdan','Tome','Kole','Vangel','Naum','Gligor','Stanko','Rade','Lazo','Arsen','Milko','Pavle','Dragan','Zdravko','Ilko','Vuk','Dame','Gorancho','Stevo','Miro'] AS m_names,
     517        ARRAY['Arsova','Dimitrova','Stojanova','Petrovska','Ilievska','Trajkova','Georgieva','Kostova','Maneva','Ristova','Popova','Jovanova','Nikolova','Mitrevska','Ivanova','Sokolova','Markova','Spasova','Angelova','Vasilevska','Pavlova','Gruevska','Nikolovska','Filipova','Stefanova','Andonova','Zafirova','Koleva','Stamenova','Bojkova','Todorova','Petkova','Hristova','Kitanova','Ilieva','Ruseva','Dimovska','Miloshevska','Petreska','Arnaudova','Georgievska','Markoska','Velkova','Stojkovska','Kirovska','Zlateva','Milevska','Naceva','Spiridonova','Lazarevska','Doneva','Atanasova','Bogdanova','Simeonova','Rangelova','Gligorova','Tasevska','Pancheva','Jankova','Bogoeva'] AS f_surnames,
     518        ARRAY['Arsov','Dimitrov','Stojanov','Petrovski','Iliev','Trajkov','Georgiev','Kostov','Manev','Ristov','Popov','Jovanov','Nikolov','Mitrev','Ivanov','Sokolov','Markov','Spasov','Angelov','Vasilev','Pavlov','Gruev','Nikolovski','Filipov','Stefanov','Andonov','Zafirov','Kolev','Stamenov','Bojkov','Todorov','Petkov','Hristov','Kitanov','Rusev','Dimovski','Miloshevski','Petreski','Arnaudov','Georgievski','Markoski','Velkov','Stojkovski','Kirovski','Zlatev','Milevski','Nacev','Spiridonov','Lazarevski','Donev','Atanasov','Bogdanov','Simeonov','Rangelov','Gligorov','Tasev','Panchev','Jankov','Bogoev','Karov','Trifunov','Gavrilov','Savov','Ilkov','Vukov','Zdravkov','Stojanovski','Danev'] AS m_surnames
    529519)
    530520SELECT
    531     p.fname || ' ' || p.lname                              AS name,
    532     LOWER(p.fname || '.' || p.lname || i)                  AS username,
    533     '+3897' || (1000000 + i)                               AS phone,
    534     LOWER(p.fname || '.' || p.lname || i || '@gmail.com')  AS email,
    535     md5(random()::text)                                    AS password_hash,
    536     NOW() - (random() * interval '3 years')                AS created_at,
    537     (SELECT status_id FROM Status WHERE status_tip = 'user' AND status_text = 'active' LIMIT 1) AS status_id
     521    p.fname || ' ' || p.lname                              AS name,
     522    LOWER(p.fname || '.' || p.lname || i)                  AS username,
     523    '+3897' || (1000000 + i)                               AS phone,
     524    LOWER(p.fname || '.' || p.lname || i || '@gmail.com') AS email,
     525    md5(random()::text)                                    AS password_hash,
     526    NOW() - (random() * interval '3 years')                AS created_at,
     527    (SELECT status_id FROM Status WHERE status_tip = 'user' AND status_text = 'active' LIMIT 1) AS status_id
    538528FROM generate_series(1, 70000) i
    539          CROSS JOIN data_pools d
    540          CROSS JOIN LATERAL (
    541     SELECT
    542         CASE WHEN i % 2 = 0
    543                  THEN d.f_names[  (i % cardinality(d.f_names))   + 1]
    544              ELSE d.m_names[  (i % cardinality(d.m_names))   + 1]
    545             END AS fname,
    546         CASE WHEN i % 2 = 0
    547                  THEN d.f_surnames[(i % cardinality(d.f_surnames)) + 1]
    548              ELSE d.m_surnames[(i % cardinality(d.m_surnames)) + 1]
    549             END AS lname
    550     ) p;
    551    
     529         CROSS JOIN data_pools d
     530         CROSS JOIN LATERAL (
     531    SELECT
     532        CASE WHEN i % 2 = 0
     533                 THEN d.f_names[  (i % cardinality(d.f_names))   + 1]
     534             ELSE d.m_names[  (i % cardinality(d.m_names))   + 1]
     535            END AS fname,
     536        CASE WHEN i % 2 = 0
     537                 THEN d.f_surnames[(i % cardinality(d.f_surnames)) + 1]
     538             ELSE d.m_surnames[(i % cardinality(d.m_surnames)) + 1]
     539            END AS lname
     540    ) p;
     541   
    552542INSERT INTO Drivers (name, phone, license_number, registration_date, rating, status_id)
    553543WITH data_pools AS (
    554     SELECT
    555         ARRAY['Petar','Marko','Nikola','Stefan','Daniel','Goran','Bojan','Andrej','Filip','Viktor',
    556             'Aleksandar','Dejan','Zoran','Ilija','Dimitar','Kiril','Hristijan','Vladimir','Vasko','Riste',
    557             'Martin','Igor','Damjan','Darko','Oliver','Luka','Emil','Stojan','Vlatko','Boris',
    558             'Radoslav','Kosta','Mladen','Mile','Petre','Gjorgi','Jovan','Ivan','Sasho','Zlatko',
    559             'Bogdan','Tome','Naum','Gligor','Stanko','Rade','Lazo','Arsen','Pavle','Dragan'] AS m_names,
    560         ARRAY['Arsov','Dimitrov','Stojanov','Petrovski','Iliev','Trajkov','Georgiev','Kostov','Manev',
    561             'Ristov','Popov','Jovanov','Nikolov','Mitrev','Ivanov','Sokolov','Markov','Spasov','Angelov',
    562             'Vasilev','Pavlov','Gruev','Nikolovski','Filipov','Stefanov','Andonov','Zafirov','Kolev',
    563             'Stamenov','Bojkov','Todorov','Petkov','Hristov','Kitanov','Rusev','Dimovski','Miloshevski',
    564             'Petreski','Arnaudov','Georgievski','Markoski','Velkov','Stojkovski','Kirovski','Zlatev',
    565             'Milevski','Spiridonov','Lazarevski','Atanasov','Bogdanov'] AS m_surnames
     544    SELECT
     545        ARRAY['Petar','Marko','Nikola','Stefan','Daniel','Goran','Bojan','Andrej','Filip','Viktor',
     546            'Aleksandar','Dejan','Zoran','Ilija','Dimitar','Kiril','Hristijan','Vladimir','Vasko','Riste',
     547            'Martin','Igor','Damjan','Darko','Oliver','Luka','Emil','Stojan','Vlatko','Boris',
     548            'Radoslav','Kosta','Mladen','Mile','Petre','Gjorgi','Jovan','Ivan','Sasho','Zlatko',
     549            'Bogdan','Tome','Naum','Gligor','Stanko','Rade','Lazo','Arsen','Pavle','Dragan'] AS m_names,
     550        ARRAY['Arsov','Dimitrov','Stojanov','Petrovski','Iliev','Trajkov','Georgiev','Kostov','Manev',
     551            'Ristov','Popov','Jovanov','Nikolov','Mitrev','Ivanov','Sokolov','Markov','Spasov','Angelov',
     552            'Vasilev','Pavlov','Gruev','Nikolovski','Filipov','Stefanov','Andonov','Zafirov','Kolev',
     553            'Stamenov','Bojkov','Todorov','Petkov','Hristov','Kitanov','Rusev','Dimovski','Miloshevski',
     554            'Petreski','Arnaudov','Georgievski','Markoski','Velkov','Stojkovski','Kirovski','Zlatev',
     555            'Milevski','Spiridonov','Lazarevski','Atanasov','Bogdanov'] AS m_surnames
    566556)
    567557SELECT
    568     p.fname || ' ' || p.lname                                          AS name,
    569     '+3897' || (2000000 + i)                                           AS phone,
    570     CHR(65 + (i % 26)) || LPAD((floor(random() * 9000000) + 1000000)::int::text, 7, '0') AS license_number,
    571     (NOW() - interval '3 years' - (random() * interval '2 years'))::DATE AS registration_date,
    572     ROUND((3.5 + random() * 1.5)::numeric, 2)                          AS rating,
    573     (SELECT status_id FROM Status WHERE status_tip = 'driver' AND status_text = 'active' LIMIT 1) AS status_id
     558    p.fname || ' ' || p.lname                                          AS name,
     559    '+3897' || (2000000 + i)                                           AS phone,
     560    CHR(65 + (i % 26)) || LPAD((floor(random() * 9000000) + 1000000)::int::text, 7, '0') AS license_number,
     561    (NOW() - interval '3 years' - (random() * interval '2 years'))::DATE AS registration_date,
     562    ROUND((3.5 + random() * 1.5)::numeric, 2)                          AS rating,
     563    (SELECT status_id FROM Status WHERE status_tip = 'driver' AND status_text = 'active' LIMIT 1) AS status_id
    574564FROM generate_series(1, 200) i
    575          CROSS JOIN data_pools d
    576          CROSS JOIN LATERAL (
    577     SELECT
    578         d.m_names[(i % cardinality(d.m_names)) + 1]       AS fname,
    579         d.m_surnames[(i % cardinality(d.m_surnames)) + 1]  AS lname
    580     ) p;   
    581                                       
     565         CROSS JOIN data_pools d
     566         CROSS JOIN LATERAL (
     567    SELECT
     568        d.m_names[(i % cardinality(d.m_names)) + 1]       AS fname,
     569        d.m_surnames[(i % cardinality(d.m_surnames)) + 1] AS lname
     570    ) p;   
     571                                     
    582572
    583573INSERT INTO Admins (name, username, phone, email, password_hash, created_at, status_id)
    584574VALUES
    585     ('Aleksandar Dimitrov', 'admin.aleksandar', '+38971100001', 'aleksandar.dimitrov@taxikumanovo.mk', md5(random()::text), NOW() - interval '4 years', (SELECT status_id FROM Status WHERE status_tip = 'admin' AND status_text = 'active' LIMIT 1)),
    586     ('Marija Petrovska',    'admin.marija',     '+38971100002', 'marija.petrovska@taxikumanovo.mk',    md5(random()::text), NOW() - interval '3 years', (SELECT status_id FROM Status WHERE status_tip = 'admin' AND status_text = 'active' LIMIT 1)),
    587     ('Nikola Trajkov',      'admin.nikola',     '+38971100003', 'nikola.trajkov@taxikumanovo.mk',      md5(random()::text), NOW() - interval '3 years', (SELECT status_id FROM Status WHERE status_tip = 'admin' AND status_text = 'active' LIMIT 1)),
    588     ('Elena Georgieva',     'admin.elena',      '+38971100004', 'elena.georgieva@taxikumanovo.mk',     md5(random()::text), NOW() - interval '2 years', (SELECT status_id FROM Status WHERE status_tip = 'admin' AND status_text = 'active' LIMIT 1)),
    589     ('Stefan Iliev',        'admin.stefan',     '+38971100005', 'stefan.iliev@taxikumanovo.mk',        md5(random()::text), NOW() - interval '2 years', (SELECT status_id FROM Status WHERE status_tip = 'admin' AND status_text = 'active' LIMIT 1)),
    590     ('Ana Nikolova',        'admin.ana',        '+38971100006', 'ana.nikolova@taxikumanovo.mk',        md5(random()::text), NOW() - interval '1 year',  (SELECT status_id FROM Status WHERE status_tip = 'admin' AND status_text = 'active' LIMIT 1));
    591    
    592    
     575    ('Aleksandar Dimitrov', 'admin.aleksandar', '+38971100001', 'aleksandar.dimitrov@taxikumanovo.mk', md5(random()::text), NOW() - interval '4 years', (SELECT status_id FROM Status WHERE status_tip = 'admin' AND status_text = 'active' LIMIT 1)),
     576    ('Marija Petrovska',    'admin.marija',     '+38971100002', 'marija.petrovska@taxikumanovo.mk',    md5(random()::text), NOW() - interval '3 years', (SELECT status_id FROM Status WHERE status_tip = 'admin' AND status_text = 'active' LIMIT 1)),
     577    ('Nikola Trajkov',      'admin.nikola',     '+38971100003', 'nikola.trajkov@taxikumanovo.mk',      md5(random()::text), NOW() - interval '3 years', (SELECT status_id FROM Status WHERE status_tip = 'admin' AND status_text = 'active' LIMIT 1)),
     578    ('Elena Georgieva',     'admin.elena',      '+38971100004', 'elena.georgieva@taxikumanovo.mk',     md5(random()::text), NOW() - interval '2 years', (SELECT status_id FROM Status WHERE status_tip = 'admin' AND status_text = 'active' LIMIT 1)),
     579    ('Stefan Iliev',        'admin.stefan',     '+38971100005', 'stefan.iliev@taxikumanovo.mk',        md5(random()::text), NOW() - interval '2 years', (SELECT status_id FROM Status WHERE status_tip = 'admin' AND status_text = 'active' LIMIT 1)),
     580    ('Ana Nikolova',        'admin.ana',        '+38971100006', 'ana.nikolova@taxikumanovo.mk',        md5(random()::text), NOW() - interval '1 year', (SELECT status_id FROM Status WHERE status_tip = 'admin' AND status_text = 'active' LIMIT 1));
     581   
     582   
    593583INSERT INTO Vehicle_ownership (Plate, Traffic_permit, Color, year, vehicle_type_id)
    594584WITH colors AS (
    595     SELECT ARRAY['Crna','Bela','Siva','Srebrena','Crvena','Sina','Zelena','Beza','Kafena','Temnosina'] AS cols
     585    SELECT ARRAY['Crna','Bela','Siva','Srebrena','Crvena','Sina','Zelena','Beza','Kafena','Temnosina'] AS cols
    596586)
    597587SELECT
    598     -- Табличка: 2 букви + 3 цифри + 2 букви, пр: SK123AB
    599     'KU' ||
    600     LPAD((100 + i)::text, 4, '0') ||
    601     CHR(65 + ((i * 5) % 26)) || CHR(65 + ((i * 7) % 26))      AS Plate,
    602 
    603     -- Сообраќајна: KU + 6 цифри
    604     CHR(65 + (i % 26)) || CHR(65 + ((i * 3) % 26)) || LPAD((100000 + i)::text, 6, '0')                   AS Traffic_permit,
    605 
    606     -- Боја
    607     c.cols[(i % cardinality(c.cols)) + 1]                      AS Color,
    608 
    609     -- Година: возилата се од 2010 до 2023
    610     2010 + (i % 14)                                            AS year,
    611 
    612     -- vehicle_type_id: рандом од 1 до 50
    613     (1 + (i % 50))                                             AS vehicle_type_id
     588    -- Табличка: 2 букви + 3 цифри + 2 букви, пр: SK123AB
     589    'KU' ||
     590    LPAD((100 + i)::text, 4, '0') ||
     591    CHR(65 + ((i * 5) % 26)) || CHR(65 + ((i * 7) % 26))      AS Plate,
     592
     593    -- Сообраќајна: KU + 6 цифри
     594    CHR(65 + (i % 26)) || CHR(65 + ((i * 3) % 26)) || LPAD((100000 + i)::text, 6, '0')                   AS Traffic_permit,
     595
     596    -- Боја
     597    c.cols[(i % cardinality(c.cols)) + 1]                      AS Color,
     598
     599    -- Година: возилата се од 2010 до 2023
     600    2010 + (i % 14)                                            AS year,
     601
     602    -- vehicle_type_id: рандом од 1 до 50
     603    (1 + (i % 50))                                             AS vehicle_type_id
    614604
    615605FROM generate_series(1, 300) i
    616          CROSS JOIN colors c;
    617    
     606         CROSS JOIN colors c;
     607   
    618608INSERT INTO Active_drivers (driver_id, current_location_id, is_available, working_start, working_end,vehicle_ownership_id)
    619609SELECT
    620     d.driver_id,
    621     -- Random location_id од постоечките локации
    622     (1 + (d.driver_id % 14000))                                    AS current_location_id,
    623     -- 70% се available, 30% се зафатени
    624     CASE WHEN d.driver_id % 10 < 7 THEN true ELSE false END        AS is_available,
    625     -- Работната смена почнала пред 1-8 часа
    626     (NOW() - (random() * interval '8 hours'))::TIMESTAMP            AS working_start,
    627     -- Работната смена завршува за 2-10 часа
    628     (NOW() + (random() * interval '10 hours'))::TIMESTAMP           AS working_end,
    629     -- Да се знае кое авто моментлано го вози
    630     CASE
    631         WHEN d.driver_id < 100
    632             THEN d.driver_id + (random(0,1) * 200)
    633         ELSE d.driver_id
    634         END AS vehicle_ownership_id
     610    d.driver_id,
     611    -- Random location_id од постоечките локации
     612    (1 + (d.driver_id % 14000))                                    AS current_location_id,
     613    -- 70% се available, 30% се зафатени
     614    CASE WHEN d.driver_id % 10 < 7 THEN true ELSE false END        AS is_available,
     615    -- Работната смена почнала пред 1-8 часа
     616    (NOW() - (random() * interval '8 hours'))::TIMESTAMP            AS working_start,
     617    -- Работната смена завршува за 2-10 часа
     618    (NOW() + (random() * interval '10 hours'))::TIMESTAMP           AS working_end,
     619    -- Да се знае кое авто моментлано го вози
     620    CASE
     621        WHEN d.driver_id < 100
     622            THEN d.driver_id + (random(0,1) * 200)
     623        ELSE d.driver_id
     624        END AS vehicle_ownership_id
    635625FROM Drivers d
    636626-- Земаме само 150 од 200 возачи (75%)
     
    643633-- Sekoj vozac dobiva svoe primарно vozilo (1:1)
    644634SELECT
    645     d.driver_id,
    646     -- Voziloto se mapira deterministicki: vozac 1→vozilo 1, vozac 2→vozilo 2 ...
    647     d.driver_id AS Vehicle_ownership_id
     635    d.driver_id,
     636    -- Voziloto se mapira deterministicki: vozac 1→vozilo 1, vozac 2→vozilo 2 ...
     637    d.driver_id AS Vehicle_ownership_id
    648638FROM Drivers d
    649 WHERE d.driver_id <= 200  -- site 200 vozaci
     639WHERE d.driver_id <= 200  -- site 200 vozaci
    650640
    651641UNION ALL
     
    653643-- Prvite 100 vozaci dobivaat i vtoro vozilo (od 201 do 300)
    654644SELECT
    655     d.driver_id,
    656     d.driver_id + 200 AS Vehicle_ownership_id
     645    d.driver_id,
     646    d.driver_id + 200 AS Vehicle_ownership_id
    657647FROM Drivers d
    658648WHERE d.driver_id <= 100;
     
    660650--Rides
    661651DO $$
    662     DECLARE
    663         batch_size   INT := 1000000;
    664         total_rows   INT := 10000000;
    665         batches      INT := total_rows / batch_size;
    666         b            INT;
    667 
    668         max_user     INT;
    669         max_driver   INT;
    670         max_location INT;
    671 
    672         sid_requested   INT;
    673         sid_accepted    INT;
    674         sid_in_progress INT;
    675         sid_completed   INT;
    676         sid_cancelled   INT;
    677     BEGIN
    678         SELECT MAX(user_id)     INTO max_user     FROM Users;
    679         SELECT MAX(driver_id)   INTO max_driver   FROM Drivers;
    680         SELECT MAX(location_id) INTO max_location FROM Locations;
    681 
    682         SELECT status_id INTO sid_requested   FROM Status WHERE status_tip='ride' AND status_text='requested'   LIMIT 1;
    683         SELECT status_id INTO sid_accepted    FROM Status WHERE status_tip='ride' AND status_text='accepted'    LIMIT 1;
    684         SELECT status_id INTO sid_in_progress FROM Status WHERE status_tip='ride' AND status_text='in_progress' LIMIT 1;
    685         SELECT status_id INTO sid_completed   FROM Status WHERE status_tip='ride' AND status_text='completed'   LIMIT 1;
    686         SELECT status_id INTO sid_cancelled   FROM Status WHERE status_tip='ride' AND status_text='cancelled'   LIMIT 1;
    687 
    688         RAISE NOTICE 'max_user=%, max_driver=%, max_location=%', max_user, max_driver, max_location;
    689 
    690         FOR b IN 1..batches LOOP
    691 
    692                 INSERT INTO Rides (
    693                     user_id,
    694                     driver_id,
    695                     pickup_location_id,
    696                     dropoff_location_id,
    697                     status_id,
    698                     request_time,
    699                     pickup_time,
    700                     start_time,
    701                     end_time,
    702                     distance_km,
    703                     final_price,
    704                     discount_percentage,
    705                     vehicle_ownership_id
    706                 )
    707                 WITH
    708 
    709                     -- --------------------------------------------------------
    710                     -- CTE 1: Realna cena po vozac spored tipot na voziloto
    711                     --        Economy:  base=80,  per_km=40
    712                     --        Luxury:   base=100, per_km=60
    713                     --        Ako ima 2 vozila → go zemame luksoznoto (MAX cena)
    714                     -- --------------------------------------------------------
    715                     driver_pricing AS (
    716                         SELECT
    717                             dvo.driver_id,
    718                             MAX(pr.base_price)    AS base_price,
    719                             MAX(pr.price_per_km)  AS price_per_km,
    720                             MAX(vt.description)   AS vehicle_class
    721                         FROM Drivers_Vehicle_ownership dvo
    722                                  JOIN Vehicle_ownership vo ON dvo.Vehicle_ownership_id = vo.Vehicle_ownership_id
    723                                  JOIN Vehicle_types     vt ON vo.vehicle_type_id       = vt.vehicle_type_id
    724                                  JOIN Pricing_rules     pr ON vt.vehicle_type_id       = pr.vehicle_type_id
    725                         GROUP BY dvo.driver_id
    726                     ),
    727 
    728                     -- --------------------------------------------------------
    729                     -- CTE 2: Base pool so site ogranichuvanja primeneti
    730                     -- --------------------------------------------------------
    731                     base_pool AS (
    732                         SELECT
    733                             s.i,
    734 
    735                             -- USER / DRIVER (realni, razlichni)
    736                             1 + (s.i % max_user)                                AS user_id,
    737                             1 + ((s.i + floor(random() * 200000)+ 37)::INTEGER % max_driver)                       AS driver_id,
    738 
    739                             -- LOKACII
    740                             1 + (s.i + floor(random() * 200000))::INTEGER % max_location                          AS pickup_location_id,
    741                             1 + ((s.i + floor(random() * 200000)+ (14000 / 2))::INTEGER % max_location)    AS dropoff_location_id,
    742 
    743                             -- STATUS
    744                             CASE
    745                                 WHEN (s.i % 20) = 0         THEN sid_requested
    746                                 WHEN (s.i % 20) IN (1, 2)   THEN sid_accepted
    747                                 WHEN (s.i % 20) IN (3, 4)   THEN sid_in_progress
    748                                 WHEN (s.i % 20) IN (18, 19) THEN sid_cancelled
    749                                 ELSE                              sid_completed
    750                                 END                                                 AS status_id,
    751 
    752                             -- BASE TIME: random den (poslednite 2 godini), cas 06:00-23:00
    753                             date_trunc('day', now() - (floor(random() * 730) * interval '1 day'))
    754                                 + (21600 + floor(random() * 61200)) * interval '1 second'
    755                                 AS request_time,
    756 
    757                             -- DISTANCA: 0.5 .. 10.0 km  (OGRANICHENO NA MAX 10km)
    758                             ROUND((0.5 + random() * 9.5)::numeric, 2)          AS distance_km
    759 
    760                         FROM generate_series(
    761                                      (b - 1) * batch_size + 1,
    762                                      b      * batch_size
    763                              ) s(i)
    764                     ),
    765 
    766                     -- --------------------------------------------------------
    767                     -- CTE 3: Presmetaj popust i vreminja vrz osnova na distanca
    768                     -- --------------------------------------------------------
    769                     enriched AS (
    770                         SELECT
    771                             bp.*,
    772 
    773                             -- POPUST:
    774                             --   >= 9km  → 10%
    775                             --   <  9km  →  0%
    776                             CASE
    777                                 WHEN bp.distance_km >= 9 THEN 10.0
    778                                 ELSE                          0.0
    779                                 END                                                 AS discount_pct,
    780 
    781                             -- VREMINJA (site od ista request_time baza):
    782                             -- pickup  = request + 2..10 min
    783                             bp.request_time
    784                                 + (2 + floor(random() * 9))  * interval '1 minute'
    785                                                                                     AS pickup_time,
    786 
    787                             -- start   = request + 3..13 min  (sekogash posle pickup)
    788                             bp.request_time
    789                                 + (3 + floor(random() * 11)) * interval '1 minute'
    790                                                                                     AS start_time,
    791 
    792                             -- end     = start  + 5..15 min  (OGRANICHENO: min 5, max 15)
    793                             bp.request_time
    794                                 + (3 + floor(random() * 11)) * interval '1 minute'  -- ista start baza
    795                                 + (5 + floor(random() * 11)) * interval '1 minute'  -- + 5..15 min
    796                                                                                     AS end_time
    797 
    798                         FROM base_pool bp
    799                     )
    800 
    801                 -- --------------------------------------------------------
    802                 -- FINALEN SELECT: JOIN so realni ceni od vozacovoto vozilo
    803                 -- --------------------------------------------------------
    804                 SELECT
    805                     en.user_id,
    806                     en.driver_id,
    807                     en.pickup_location_id,
    808                     en.dropoff_location_id,
    809                     en.status_id,
    810 
    811                     en.request_time,
    812                     en.pickup_time,
    813                     en.start_time,
    814                     en.end_time,
    815 
    816                     en.distance_km,
    817 
    818                     -- CENA spored tipot na voziloto:
    819                     --   Economy → (80  + km * 40) * (1 - popust%)
    820                     --   Luxury  → (100 + km * 60) * (1 - popust%)
    821                     --   Ako vozacot nema vozilo → fallback na Economy cena
    822                     ROUND(
    823                             (COALESCE(dp.base_price, 80) + en.distance_km * COALESCE(dp.price_per_km, 40))
    824                                 * (1.0 - en.discount_pct / 100.0)
    825                                 ::numeric, 2)                                           AS final_price,
    826 
    827                     en.discount_pct                                         AS discount_percentage,
    828                     CASE
    829                         WHEN en.driver_id < 100
    830                             THEN en.driver_id + (random(0,1) * 200)
    831                         ELSE 
    832                             en.driver_id 
    833                         END AS vehicle_ownership_id
    834 
    835 
    836                 FROM enriched en
    837                          LEFT JOIN driver_pricing dp ON en.driver_id = dp.driver_id;
    838 
    839                 RAISE NOTICE 'Batch % / % zavrshen — % redovi vkupno', b, batches, b * batch_size;
    840 
    841             END LOOP;
    842 
    843         update rides set pickup_location_id = 1 + (Rides.ride_id + floor(random() * 200000))::INTEGER% max_location
    844         where  dropoff_location_id=pickup_location_id;
    845 
    846         RAISE NOTICE '*** GOTOVO: 10 000 000 redovi vo Rides ***';
    847     END $$;
    848    
    849 --Payments   
     652    DECLARE
     653        batch_size   INT := 1000000;
     654        total_rows   INT := 10000000;
     655        batches      INT := total_rows / batch_size;
     656        b            INT;
     657
     658        max_user     INT;
     659        max_driver   INT;
     660        max_location INT;
     661
     662        sid_requested   INT;
     663        sid_accepted    INT;
     664        sid_in_progress INT;
     665        sid_completed   INT;
     666        sid_cancelled   INT;
     667    BEGIN
     668        SELECT MAX(user_id)     INTO max_user     FROM Users;
     669        SELECT MAX(driver_id)   INTO max_driver   FROM Drivers;
     670        SELECT MAX(location_id) INTO max_location FROM Locations;
     671
     672        SELECT status_id INTO sid_requested   FROM Status WHERE status_tip='ride' AND status_text='requested'   LIMIT 1;
     673        SELECT status_id INTO sid_accepted    FROM Status WHERE status_tip='ride' AND status_text='accepted'    LIMIT 1;
     674        SELECT status_id INTO sid_in_progress FROM Status WHERE status_tip='ride' AND status_text='in_progress' LIMIT 1;
     675        SELECT status_id INTO sid_completed   FROM Status WHERE status_tip='ride' AND status_text='completed'   LIMIT 1;
     676        SELECT status_id INTO sid_cancelled   FROM Status WHERE status_tip='ride' AND status_text='cancelled'   LIMIT 1;
     677
     678        RAISE NOTICE 'max_user=%, max_driver=%, max_location=%', max_user, max_driver, max_location;
     679
     680        FOR b IN 1..batches LOOP
     681
     682                INSERT INTO Rides (
     683                    user_id,
     684                    driver_id,
     685                    pickup_location_id,
     686                    dropoff_location_id,
     687                    status_id,
     688                    request_time,
     689                    pickup_time,
     690                    start_time,
     691                    end_time,
     692                    distance_km,
     693                    final_price,
     694                    discount_percentage,
     695                    vehicle_ownership_id
     696                )
     697                WITH
     698
     699                    -- --------------------------------------------------------
     700                    -- CTE 1: Realna cena po vozac spored tipot na voziloto
     701                    --        Economy:  base=80, per_km=40
     702                    --        Luxury:   base=100, per_km=60
     703                    --        Ako ima 2 vozila → go zemame luksoznoto (MAX cena)
     704                    -- --------------------------------------------------------
     705                    driver_pricing AS (
     706                        SELECT
     707                            dvo.driver_id,
     708                            MAX(pr.base_price)    AS base_price,
     709                            MAX(pr.price_per_km) AS price_per_km,
     710                            MAX(vt.description)   AS vehicle_class
     711                        FROM Drivers_Vehicle_ownership dvo
     712                                 JOIN Vehicle_ownership vo ON dvo.Vehicle_ownership_id = vo.Vehicle_ownership_id
     713                                 JOIN Vehicle_types     vt ON vo.vehicle_type_id       = vt.vehicle_type_id
     714                                 JOIN Pricing_rules     pr ON vt.vehicle_type_id       = pr.vehicle_type_id
     715                        GROUP BY dvo.driver_id
     716                    ),
     717
     718                    -- --------------------------------------------------------
     719                    -- CTE 2: Base pool so site ogranichuvanja primeneti
     720                    -- --------------------------------------------------------
     721                    base_pool AS (
     722                        SELECT
     723                            s.i,
     724
     725                            -- USER / DRIVER (realni, razlichni)
     726                            1 + (s.i % max_user)                                                AS user_id,
     727                            1 + ((s.i + floor(random() * 200000)+ 37)::INTEGER % max_driver)                       AS driver_id,
     728
     729                            -- LOKACII
     730                            1 + (s.i + floor(random() * 200000))::INTEGER % max_location                          AS pickup_location_id,
     731                            1 + ((s.i + floor(random() * 200000)+ (14000 / 2))::INTEGER % max_location)    AS dropoff_location_id,
     732
     733                            -- STATUS
     734                            CASE
     735                                WHEN (s.i % 20) = 0         THEN sid_requested
     736                                WHEN (s.i % 20) IN (1, 2)   THEN sid_accepted
     737                                WHEN (s.i % 20) IN (3, 4)   THEN sid_in_progress
     738                                WHEN (s.i % 20) IN (18, 19) THEN sid_cancelled
     739                                ELSE                              sid_completed
     740                                END                                                                 AS status_id,
     741
     742                            -- BASE TIME: random den (poslednite 2 godini), cas 06:00-23:00
     743                            date_trunc('day', now() - (floor(random() * 730) * interval '1 day'))
     744                                + (21600 + floor(random() * 61200)) * interval '1 second'
     745                                AS request_time,
     746
     747                            -- DISTANCA: 0.5 .. 10.0 km (OGRANICHENO NA MAX 10km)
     748                            ROUND((0.5 + random() * 9.5)::numeric, 2)          AS distance_km
     749
     750                        FROM generate_series(
     751                                     (b - 1) * batch_size + 1,
     752                                     b      * batch_size
     753                             ) s(i)
     754                    ),
     755
     756                    -- --------------------------------------------------------
     757                    -- CTE 3: Presmetaj popust i vreminja vrz osnova na distanca
     758                    -- --------------------------------------------------------
     759                    enriched AS (
     760                        SELECT
     761                            bp.*,
     762
     763                            -- POPUST:
     764                            --   >= 9km → 10%
     765                            --   <  9km  → 0%
     766                            CASE
     767                                WHEN bp.distance_km >= 9 THEN 10.0
     768                                ELSE                          0.0
     769                                END                                                 AS discount_pct,
     770
     771                            -- VREMINJA (site od ista request_time baza):
     772                            -- pickup = request + 2..10 min
     773                            bp.request_time
     774                                + (2 + floor(random() * 9)) * interval '1 minute'
     775                                                                                                AS pickup_time,
     776
     777                            -- start   = request + 3..13 min (sekogash posle pickup)
     778                            bp.request_time
     779                                + (3 + floor(random() * 11)) * interval '1 minute'
     780                                                                                                AS start_time,
     781
     782                            -- end     = start  + 5..15 min (OGRANICHENO: min 5, max 15)
     783                            bp.request_time
     784                                + (3 + floor(random() * 11)) * interval '1 minute' -- ista start baza
     785                                + (5 + floor(random() * 11)) * interval '1 minute' -- + 5..15 min
     786                                                                                                AS end_time
     787
     788                        FROM base_pool bp
     789                    )
     790
     791                -- --------------------------------------------------------
     792                -- FINALEN SELECT: JOIN so realni ceni od vozacovoto vozilo
     793                -- --------------------------------------------------------
     794                SELECT
     795                    en.user_id,
     796                    en.driver_id,
     797                    en.pickup_location_id,
     798                    en.dropoff_location_id,
     799                    en.status_id,
     800
     801                    en.request_time,
     802                    en.pickup_time,
     803                    en.start_time,
     804                    en.end_time,
     805
     806                    en.distance_km,
     807
     808                    -- CENA spored tipot na voziloto:
     809                    --   Economy → (80 + km * 40) * (1 - popust%)
     810                    --   Luxury → (100 + km * 60) * (1 - popust%)
     811                    --   Ako vozacot nema vozilo → fallback na Economy cena
     812                    ROUND(
     813                            (COALESCE(dp.base_price, 80) + en.distance_km * COALESCE(dp.price_per_km, 40))
     814                                * (1.0 - en.discount_pct / 100.0)
     815                                ::numeric, 2)                                           AS final_price,
     816
     817                    en.discount_pct                                         AS discount_percentage,
     818                    CASE
     819                        WHEN en.driver_id < 100
     820                            THEN en.driver_id + (random(0,1) * 200)
     821                        ELSE
     822                            en.driver_id
     823                        END AS vehicle_ownership_id
     824
     825
     826                FROM enriched en
     827                         LEFT JOIN driver_pricing dp ON en.driver_id = dp.driver_id;
     828
     829                RAISE NOTICE 'Batch % / % zavrshen — % redovi vkupno', b, batches, b * batch_size;
     830
     831            END LOOP;
     832
     833        update rides set pickup_location_id = 1 + (Rides.ride_id + floor(random() * 200000))::INTEGER% max_location
     834        where dropoff_location_id=pickup_location_id;
     835
     836        RAISE NOTICE '*** GOTOVO: 10 000 000 redovi vo Rides ***';
     837    END $$;
     838   
     839--Payments   
    850840DO $$
    851     DECLARE
    852         batch_size  INT := 1000000;
    853         total_rows  INT := 10000000;
    854         batches     INT := total_rows / batch_size;
    855         b           INT;
    856 
    857         -- Payment method IDs
    858         pm_cash     INT;
    859         pm_card     INT;
    860 
    861         -- Payment status IDs
    862         sid_pending   INT;
    863         sid_completed INT;
    864         sid_failed    INT;
    865         sid_refunded  INT;
    866 
    867         -- Ride status IDs (za da odredime payment status)
    868         rid_completed   INT;
    869         rid_cancelled   INT;
    870 
    871     BEGIN
    872         -- Payment methods
    873         SELECT payment_method_id INTO pm_cash FROM Payment_methods WHERE payment_tip = 'CASH' LIMIT 1;
    874         SELECT payment_method_id INTO pm_card FROM Payment_methods WHERE payment_tip = 'CARD' LIMIT 1;
    875 
    876         -- Payment statusi
    877         SELECT status_id INTO sid_pending   FROM Status WHERE status_tip='payment' AND status_text='pending'   LIMIT 1;
    878         SELECT status_id INTO sid_completed FROM Status WHERE status_tip='payment' AND status_text='completed' LIMIT 1;
    879         SELECT status_id INTO sid_failed    FROM Status WHERE status_tip='payment' AND status_text='failed'    LIMIT 1;
    880         SELECT status_id INTO sid_refunded  FROM Status WHERE status_tip='payment' AND status_text='refunded'  LIMIT 1;
    881 
    882         -- Ride statusi
    883         SELECT status_id INTO rid_completed FROM Status WHERE status_tip='ride' AND status_text='completed'  LIMIT 1;
    884         SELECT status_id INTO rid_cancelled FROM Status WHERE status_tip='ride' AND status_text='cancelled'  LIMIT 1;
    885 
    886         RAISE NOTICE 'pm_cash=%, pm_card=%', pm_cash, pm_card;
    887         RAISE NOTICE 'payment statusi: pending=%, completed=%, failed=%, refunded=%',
    888             sid_pending, sid_completed, sid_failed, sid_refunded;
    889 
    890         FOR b IN 1..batches LOOP
    891 
    892                 INSERT INTO Payments (
    893                     amount,
    894                     payment_method_id,
    895                     payment_time,
    896                     ride_id,
    897                     status_id
    898                 )
    899                 SELECT
    900                     -- Amount = tocnata cena od ridot
    901                     r.final_price                                               AS amount,
    902 
    903                     -- Payment method: 60% CASH, 40% CARD
    904                     CASE
    905                         WHEN (r.ride_id % 10) < 6 THEN pm_cash
    906                         ELSE                           pm_card
    907                         END                                                         AS payment_method_id,
    908 
    909                     -- Payment time = end_time + 1..5 min
    910                     r.end_time + (1 + floor(random() * 5)) * interval '1 minute'
    911                         AS payment_time,
    912 
    913                     r.ride_id                                                   AS ride_id,
    914 
    915                     -- Payment status spored status na ridot:
    916                     --   completed   → completed
    917                     --   cancelled   → 50% failed, 50% refunded
    918                     --   site drugi  → pending
    919                     CASE
    920                         WHEN r.status_id = rid_completed THEN sid_completed
    921                         WHEN r.status_id = rid_cancelled THEN
    922                             CASE WHEN r.ride_id % 2 = 0 THEN sid_failed
    923                                  ELSE                        sid_refunded
    924                                 END
    925                         ELSE sid_pending
    926                         END                                                         AS status_id
    927 
    928                 FROM Rides r
    929                 WHERE r.ride_id BETWEEN (b - 1) * batch_size + 1
    930                           AND b       * batch_size;
    931 
    932                 RAISE NOTICE 'Batch % / % zavrshen — % payments vkupno', b, batches, b * batch_size;
    933 
    934             END LOOP;
    935 
    936         RAISE NOTICE '*** GOTOVO: 10 000 000 redovi vo Payments ***';
    937     END $$;
    938    
     841    DECLARE
     842        batch_size INT := 1000000;
     843        total_rows INT := 10000000;
     844        batches     INT := total_rows / batch_size;
     845        b           INT;
     846
     847        -- Payment method IDs
     848        pm_cash     INT;
     849        pm_card     INT;
     850
     851        -- Payment status IDs
     852        sid_pending   INT;
     853        sid_completed INT;
     854        sid_failed    INT;
     855        sid_refunded INT;
     856
     857        -- Ride status IDs (za da odredime payment status)
     858        rid_completed   INT;
     859        rid_cancelled   INT;
     860
     861    BEGIN
     862        -- Payment methods
     863        SELECT payment_method_id INTO pm_cash FROM Payment_methods WHERE payment_tip = 'CASH' LIMIT 1;
     864        SELECT payment_method_id INTO pm_card FROM Payment_methods WHERE payment_tip = 'CARD' LIMIT 1;
     865
     866        -- Payment statusi
     867        SELECT status_id INTO sid_pending   FROM Status WHERE status_tip='payment' AND status_text='pending'   LIMIT 1;
     868        SELECT status_id INTO sid_completed FROM Status WHERE status_tip='payment' AND status_text='completed' LIMIT 1;
     869        SELECT status_id INTO sid_failed    FROM Status WHERE status_tip='payment' AND status_text='failed'    LIMIT 1;
     870        SELECT status_id INTO sid_refunded  FROM Status WHERE status_tip='payment' AND status_text='refunded' LIMIT 1;
     871
     872        -- Ride statusi
     873        SELECT status_id INTO rid_completed FROM Status WHERE status_tip='ride' AND status_text='completed' LIMIT 1;
     874        SELECT status_id INTO rid_cancelled FROM Status WHERE status_tip='ride' AND status_text='cancelled' LIMIT 1;
     875
     876        RAISE NOTICE 'pm_cash=%, pm_card=%', pm_cash, pm_card;
     877        RAISE NOTICE 'payment statusi: pending=%, completed=%, failed=%, refunded=%',
     878            sid_pending, sid_completed, sid_failed, sid_refunded;
     879
     880        FOR b IN 1..batches LOOP
     881
     882                INSERT INTO Payments (
     883                    amount,
     884                    payment_method_id,
     885                    payment_time,
     886                    ride_id,
     887                    status_id
     888                )
     889                SELECT
     890                    -- Amount = tocnata cena od ridot
     891                    r.final_price                                                               AS amount,
     892
     893                    -- Payment method: 60% CASH, 40% CARD
     894                    CASE
     895                        WHEN (r.ride_id % 10) < 6 THEN pm_cash
     896                        ELSE                           pm_card
     897                        END                                                             AS payment_method_id,
     898
     899                    -- Payment time = end_time + 1..5 min
     900                    r.end_time + (1 + floor(random() * 5)) * interval '1 minute'
     901                        AS payment_time,
     902
     903                    r.ride_id                                                                   AS ride_id,
     904
     905                    -- Payment status spored status na ridot:
     906                    --   completed   → completed
     907                    --   cancelled   → 50% failed, 50% refunded
     908                    --   site drugi → pending
     909                    CASE
     910                        WHEN r.status_id = rid_completed THEN sid_completed
     911                        WHEN r.status_id = rid_cancelled THEN
     912                            CASE WHEN r.ride_id % 2 = 0 THEN sid_failed
     913                                 ELSE                        sid_refunded
     914                                END
     915                        ELSE sid_pending
     916                        END                                                             AS status_id
     917
     918                FROM Rides r
     919                WHERE r.ride_id BETWEEN (b - 1) * batch_size + 1
     920                          AND b       * batch_size;
     921
     922                RAISE NOTICE 'Batch % / % zavrshen — % payments vkupno', b, batches, b * batch_size;
     923
     924            END LOOP;
     925
     926        RAISE NOTICE '*** GOTOVO: 10 000 000 redovi vo Payments ***';
     927    END $$;
     928   
    939929INSERT INTO Cancellations (
    940     cancelled_by_type,
    941     cancelled_by_id,
    942     reason,
    943     cancellation_fee,
    944     created_at,
    945     ride_id
     930    cancelled_by_type,
     931    cancelled_by_id,
     932    reason,
     933    cancellation_fee,
     934    created_at,
     935    ride_id
    946936)
    947937WITH
     
    949939-- Ride status za cancelled
    950940cancelled_status AS (
    951     SELECT status_id FROM Status WHERE status_tip='ride' AND status_text='cancelled' LIMIT 1
     941    SELECT status_id FROM Status WHERE status_tip='ride' AND status_text='cancelled' LIMIT 1
    952942),
    953943
    954944-- Realna base_price po vozac (Economy=80, Luxury=100)
    955945driver_pricing AS (
    956     SELECT
    957         dvo.driver_id,
    958         MAX(pr.base_price) AS base_price
    959     FROM Drivers_Vehicle_ownership dvo
    960              JOIN Vehicle_ownership vo ON dvo.Vehicle_ownership_id = vo.Vehicle_ownership_id
    961              JOIN Vehicle_types     vt ON vo.vehicle_type_id       = vt.vehicle_type_id
    962              JOIN Pricing_rules     pr ON vt.vehicle_type_id       = pr.vehicle_type_id
    963     GROUP BY dvo.driver_id
     946    SELECT
     947        dvo.driver_id,
     948        MAX(pr.base_price) AS base_price
     949    FROM Drivers_Vehicle_ownership dvo
     950             JOIN Vehicle_ownership vo ON dvo.Vehicle_ownership_id = vo.Vehicle_ownership_id
     951             JOIN Vehicle_types     vt ON vo.vehicle_type_id       = vt.vehicle_type_id
     952             JOIN Pricing_rules     pr ON vt.vehicle_type_id       = pr.vehicle_type_id
     953    GROUP BY dvo.driver_id
    964954),
    965955
    966956-- Samo cancelled rides + row_number za ramномерна distribucija
    967957cancelled_rides AS (
    968     SELECT
    969         r.ride_id,
    970         r.user_id,
    971         r.driver_id,
    972         r.request_time,
    973         COALESCE(dp.base_price, 80)             AS base_price,
    974         -- row_number() garantira 0..9 ramномерно bez zavisnost od ride_id vrednostite
    975         (row_number() OVER (ORDER BY r.ride_id) - 1) % 10   AS rn
    976     FROM Rides r
    977              JOIN cancelled_status cs ON r.status_id = cs.status_id
    978              LEFT JOIN driver_pricing dp ON r.driver_id = dp.driver_id
     958    SELECT
     959        r.ride_id,
     960        r.user_id,
     961        r.driver_id,
     962        r.request_time,
     963        COALESCE(dp.base_price, 80)             AS base_price,
     964        -- row_number() garantira 0..9 ramномерно bez zavisnost od ride_id vrednostite
     965        (row_number() OVER (ORDER BY r.ride_id) - 1) % 10   AS rn
     966    FROM Rides r
     967             JOIN cancelled_status cs ON r.status_id = cs.status_id
     968             LEFT JOIN driver_pricing dp ON r.driver_id = dp.driver_id
    979969)
    980970
    981971SELECT
    982     -- cancelled_by_type: 50% USER (0-4), 30% DRIVER (5-7), 20% ADMIN (8-9)
    983     CASE
    984         WHEN rn IN (0,1,2,3,4) THEN 'USER'
    985         WHEN rn IN (5,6,7)     THEN 'DRIVER'
    986         ELSE                        'ADMIN'
    987         END                                                         AS cancelled_by_type,
    988 
    989     -- cancelled_by_id: realen ID
    990     CASE
    991         WHEN rn IN (0,1,2,3,4) THEN user_id
    992         WHEN rn IN (5,6,7)     THEN driver_id
    993         ELSE                        1 + (ride_id % 6)
    994         END                                                         AS cancelled_by_id,
    995 
    996     -- Reason spored tipot
    997     CASE
    998         WHEN rn IN (0,1,2,3,4) THEN
    999             CASE (ride_id % 3)
    1000                 WHEN 0 THEN 'Променив планови и повеќе не ми треба превоз'
    1001                 WHEN 1 THEN 'Чекањето беше предолго'
    1002                 ELSE        'Внесов погрешна локација за подигање'
    1003                 END
    1004         WHEN rn IN (5,6,7) THEN
    1005             CASE (ride_id % 3)
    1006                 WHEN 0 THEN 'Не можам да ја пронајдам точната локација на патникот'
    1007                 WHEN 1 THEN 'Патникот не се појави на местото за подигање'
    1008                 ELSE        'Технички проблем со возилото'
    1009                 END
    1010         ELSE
    1011             CASE (ride_id % 3)
    1012                 WHEN 0 THEN 'Вожњата е откажана поради сомнителна активност'
    1013                 WHEN 1 THEN 'Откажано поради дупликат барање'
    1014                 ELSE        'Откажано поради системска грешка'
    1015                 END
    1016         END                                                         AS reason,
    1017 
    1018     -- Fee: samo USER plaka, Driver i Admin = 0
    1019     CASE
    1020         WHEN rn IN (0,1,2,3,4) THEN base_price
    1021         ELSE                        0.00
    1022         END                                                         AS cancellation_fee,
    1023 
    1024     -- created_at = request_time + 1..30 min
    1025     request_time + (1 + floor(random() * 30)) * interval '1 minute'
    1026                                                                     AS created_at,
    1027 
    1028     ride_id
    1029 FROM cancelled_rides;        
    1030 
    1031    
     972    -- cancelled_by_type: 50% USER (0-4), 30% DRIVER (5-7), 20% ADMIN (8-9)
     973    CASE
     974        WHEN rn IN (0,1,2,3,4) THEN 'USER'
     975        WHEN rn IN (5,6,7)     THEN 'DRIVER'
     976        ELSE                        'ADMIN'
     977        END                                                             AS cancelled_by_type,
     978
     979    -- cancelled_by_id: realen ID
     980    CASE
     981        WHEN rn IN (0,1,2,3,4) THEN user_id
     982        WHEN rn IN (5,6,7)     THEN driver_id
     983        ELSE                        1 + (ride_id % 6)
     984        END                                                             AS cancelled_by_id,
     985
     986    -- Reason spored tipot
     987    CASE
     988        WHEN rn IN (0,1,2,3,4) THEN
     989            CASE (ride_id % 3)
     990                WHEN 0 THEN 'Променив планови и повеќе не ми треба превоз'
     991                WHEN 1 THEN 'Чекањето беше предолго'
     992                ELSE        'Внесов погрешна локација за подигање'
     993                END
     994        WHEN rn IN (5,6,7) THEN
     995            CASE (ride_id % 3)
     996                WHEN 0 THEN 'Не можам да ја пронајдам точната локација на патникот'
     997                WHEN 1 THEN 'Патникот не се појави на местото за подигање'
     998                ELSE        'Технички проблем со возилото'
     999                END
     1000        ELSE
     1001            CASE (ride_id % 3)
     1002                WHEN 0 THEN 'Вожњата е откажана поради сомнителна активност'
     1003                WHEN 1 THEN 'Откажано поради дупликат барање'
     1004                ELSE        'Откажано поради системска грешка'
     1005                END
     1006        END                                                             AS reason,
     1007
     1008    -- Fee: samo USER plaka, Driver i Admin = 0
     1009    CASE
     1010        WHEN rn IN (0,1,2,3,4) THEN base_price
     1011        ELSE                        0.00
     1012        END                                                             AS cancellation_fee,
     1013
     1014    -- created_at = request_time + 1..30 min
     1015    request_time + (1 + floor(random() * 30)) * interval '1 minute'
     1016                                                                    AS created_at,
     1017
     1018    ride_id
     1019FROM cancelled_rides;       
     1020
     1021   
    10321022
    10331023DO $$
    1034     DECLARE
    1035         batch_size INT := 500000;
    1036         b          INT;
    1037         max_ride   INT;
    1038         batches    INT;
    1039 
    1040         mid_1 INT; mid_2 INT; mid_3 INT; mid_4 INT;
    1041         mid_5 INT; mid_6 INT; mid_7 INT; mid_8 INT; mid_9 INT;
    1042 
    1043         sid_notif_sent   INT;
    1044         sid_notif_fail   INT;
    1045 
    1046         rid_completed   INT;
    1047         rid_cancelled   INT;
    1048         rid_in_progress INT;
    1049         rid_accepted    INT;
    1050         rid_requested   INT;
    1051 
    1052         pay_completed INT;
    1053         pay_failed    INT;
    1054     BEGIN
    1055         -- Message IDs
    1056         SELECT message_id INTO mid_1 FROM Messages WHERE message_text LIKE 'Vaseto baranje e uspesno%'                LIMIT 1;
    1057         SELECT message_id INTO mid_2 FROM Messages WHERE message_text LIKE 'Vozacot go prifati%'                      LIMIT 1;
    1058         SELECT message_id INTO mid_3 FROM Messages WHERE message_text LIKE 'Vozacot go odbi%'                         LIMIT 1;
    1059         SELECT message_id INTO mid_4 FROM Messages WHERE message_text LIKE 'Vozacot pristigna%'                       LIMIT 1;
    1060         SELECT message_id INTO mid_5 FROM Messages WHERE message_text LIKE 'Vozenjeto e otkazano od strana na vozac%' LIMIT 1;
    1061         SELECT message_id INTO mid_6 FROM Messages WHERE message_text LIKE 'Vozenjeto e otkazano od vasa%'            LIMIT 1;
    1062         SELECT message_id INTO mid_7 FROM Messages WHERE message_text LIKE 'Plakjanjeto e uspesno%'                   LIMIT 1;
    1063         SELECT message_id INTO mid_8 FROM Messages WHERE message_text LIKE 'Plakjanjeto ne uspea%'                    LIMIT 1;
    1064         SELECT message_id INTO mid_9 FROM Messages WHERE message_text LIKE 'Nemate dostapni%'                         LIMIT 1;
    1065 
    1066         -- Notification statusi (koristime ride status kako proxy za sent/fail)
    1067         SELECT status_id INTO sid_notif_sent FROM Status WHERE status_tip='ride' AND status_text='completed' LIMIT 1;
    1068         SELECT status_id INTO sid_notif_fail FROM Status WHERE status_tip='ride' AND status_text='cancelled' LIMIT 1;
    1069 
    1070         -- Ride statusi
    1071         SELECT status_id INTO rid_completed   FROM Status WHERE status_tip='ride' AND status_text='completed'   LIMIT 1;
    1072         SELECT status_id INTO rid_cancelled   FROM Status WHERE status_tip='ride' AND status_text='cancelled'   LIMIT 1;
    1073         SELECT status_id INTO rid_in_progress FROM Status WHERE status_tip='ride' AND status_text='in_progress' LIMIT 1;
    1074         SELECT status_id INTO rid_accepted    FROM Status WHERE status_tip='ride' AND status_text='accepted'    LIMIT 1;
    1075         SELECT status_id INTO rid_requested   FROM Status WHERE status_tip='ride' AND status_text='requested'   LIMIT 1;
    1076 
    1077         -- Payment statusi
    1078         SELECT status_id INTO pay_completed FROM Status WHERE status_tip='payment' AND status_text='completed' LIMIT 1;
    1079         SELECT status_id INTO pay_failed    FROM Status WHERE status_tip='payment' AND status_text='failed'    LIMIT 1;
    1080 
    1081         SELECT MAX(ride_id) INTO max_ride FROM Rides;
    1082         batches := CEIL(max_ride::numeric / batch_size);
    1083 
    1084         RAISE NOTICE 'Pocnuvame so % batches po % rides', batches, batch_size;
    1085 
    1086         -- ===========================================================
    1087         --  FLOW 1: COMPLETED rides
    1088         --  Poraki: 1→2→4→7
    1089         --  Vreminja: request→pickup→start→end+2min
    1090         -- ===========================================================
    1091         FOR b IN 1..batches LOOP
    1092                 INSERT INTO Notifications (message_id, sent_time, user_id, ride_id, status_id)
    1093                 SELECT * FROM (
    1094 
    1095                                   -- Poraka 1: Baranjeto e uspesno isprateno → request_time
    1096                                   SELECT mid_1, r.request_time, r.user_id, r.ride_id, sid_notif_sent
    1097                                   FROM Rides r
    1098                                   WHERE r.ride_id BETWEEN (b-1)*batch_size+1 AND b*batch_size
    1099                                     AND r.status_id = rid_completed
    1100 
    1101                                   UNION ALL
    1102 
    1103                                   -- Poraka 2: Vozacot go prifati → pickup_time
    1104                                   SELECT mid_2, r.pickup_time, r.user_id, r.ride_id, sid_notif_sent
    1105                                   FROM Rides r
    1106                                   WHERE r.ride_id BETWEEN (b-1)*batch_size+1 AND b*batch_size
    1107                                     AND r.status_id = rid_completed
    1108 
    1109                                   UNION ALL
    1110 
    1111                                   -- Poraka 4: Vozacot pristigna → start_time
    1112                                   SELECT mid_4, r.start_time, r.user_id, r.ride_id, sid_notif_sent
    1113                                   FROM Rides r
    1114                                   WHERE r.ride_id BETWEEN (b-1)*batch_size+1 AND b*batch_size
    1115                                     AND r.status_id = rid_completed
    1116 
    1117                                   UNION ALL
    1118 
    1119                                   -- Poraka 7: Plakjanjeto uspesno → end_time + 2..5 min
    1120                                   SELECT mid_7,
    1121                                          r.end_time + (2 + floor(random()*4)) * interval '1 minute',
    1122                                          r.user_id, r.ride_id, sid_notif_sent
    1123                                   FROM Rides r
    1124                                            JOIN Payments p ON r.ride_id = p.ride_id AND p.status_id = pay_completed
    1125                                   WHERE r.ride_id BETWEEN (b-1)*batch_size+1 AND b*batch_size
    1126                                     AND r.status_id = rid_completed
    1127 
    1128                               ) flows;
    1129 
    1130                 RAISE NOTICE '[COMPLETED] Batch % / %', b, batches;
    1131             END LOOP;
    1132 
    1133         -- ===========================================================
    1134         --  FLOW 2: CANCELLED BY USER
    1135         --  Poraki: 1→6→8
    1136         --  Vreminja: request→request+1..10min→end+2min
    1137         -- ===========================================================
    1138         FOR b IN 1..batches LOOP
    1139                 INSERT INTO Notifications (message_id, sent_time, user_id, ride_id, status_id)
    1140                 SELECT * FROM (
    1141 
    1142                                   -- Poraka 1: Baranjeto isprateno → request_time
    1143                                   SELECT mid_1, r.request_time, r.user_id, r.ride_id, sid_notif_sent
    1144                                   FROM Rides r
    1145                                            JOIN Cancellations c ON r.ride_id = c.ride_id AND c.cancelled_by_type = 'USER'
    1146                                   WHERE r.ride_id BETWEEN (b-1)*batch_size+1 AND b*batch_size
    1147                                     AND r.status_id = rid_cancelled
    1148 
    1149                                   UNION ALL
    1150 
    1151                                   -- Poraka 6: Otkazano od vasa strana → request_time + 1..10 min
    1152                                   SELECT mid_6,
    1153                                          r.request_time + (1 + floor(random()*10)) * interval '1 minute',
    1154                                          r.user_id, r.ride_id, sid_notif_fail
    1155                                   FROM Rides r
    1156                                            JOIN Cancellations c ON r.ride_id = c.ride_id AND c.cancelled_by_type = 'USER'
    1157                                   WHERE r.ride_id BETWEEN (b-1)*batch_size+1 AND b*batch_size
    1158                                     AND r.status_id = rid_cancelled
    1159 
    1160                                   UNION ALL
    1161 
    1162                                   -- Poraka 8: Plakjanjeto ne uspea → end_time + 2..5 min
    1163                                   SELECT mid_8,
    1164                                          r.end_time + (2 + floor(random()*4)) * interval '1 minute',
    1165                                          r.user_id, r.ride_id, sid_notif_fail
    1166                                   FROM Rides r
    1167                                            JOIN Payments p ON r.ride_id = p.ride_id AND p.status_id = pay_failed
    1168                                            JOIN Cancellations c ON r.ride_id = c.ride_id AND c.cancelled_by_type = 'USER'
    1169                                   WHERE r.ride_id BETWEEN (b-1)*batch_size+1 AND b*batch_size
    1170                                     AND r.status_id = rid_cancelled
    1171 
    1172                               ) flows;
    1173 
    1174                 RAISE NOTICE '[CANCELLED USER] Batch % / %', b, batches;
    1175             END LOOP;
    1176 
    1177         -- ===========================================================
    1178         --  FLOW 3: CANCELLED BY DRIVER
    1179         --  Poraki: 1→2→5
    1180         --  Vreminja: request→pickup→request+5..15min
    1181         -- ===========================================================
    1182         FOR b IN 1..batches LOOP
    1183                 INSERT INTO Notifications (message_id, sent_time, user_id, ride_id, status_id)
    1184                 SELECT * FROM (
    1185 
    1186                                   -- Poraka 1: Baranjeto isprateno → request_time
    1187                                   SELECT mid_1, r.request_time, r.user_id, r.ride_id, sid_notif_sent
    1188                                   FROM Rides r
    1189                                            JOIN Cancellations c ON r.ride_id = c.ride_id AND c.cancelled_by_type = 'DRIVER'
    1190                                   WHERE r.ride_id BETWEEN (b-1)*batch_size+1 AND b*batch_size
    1191                                     AND r.status_id = rid_cancelled
    1192 
    1193                                   UNION ALL
    1194 
    1195                                   -- Poraka 2: Vozacot prifati → pickup_time
    1196                                   SELECT mid_2, r.pickup_time, r.user_id, r.ride_id, sid_notif_sent
    1197                                   FROM Rides r
    1198                                            JOIN Cancellations c ON r.ride_id = c.ride_id AND c.cancelled_by_type = 'DRIVER'
    1199                                   WHERE r.ride_id BETWEEN (b-1)*batch_size+1 AND b*batch_size
    1200                                     AND r.status_id = rid_cancelled
    1201 
    1202                                   UNION ALL
    1203 
    1204                                   -- Poraka 5: Otkazano od vozac → request_time + 5..15 min
    1205                                   SELECT mid_5,
    1206                                          r.request_time + (5 + floor(random()*11)) * interval '1 minute',
    1207                                          r.user_id, r.ride_id, sid_notif_fail
    1208                                   FROM Rides r
    1209                                            JOIN Cancellations c ON r.ride_id = c.ride_id AND c.cancelled_by_type = 'DRIVER'
    1210                                   WHERE r.ride_id BETWEEN (b-1)*batch_size+1 AND b*batch_size
    1211                                     AND r.status_id = rid_cancelled
    1212 
    1213                               ) flows;
    1214 
    1215                 RAISE NOTICE '[CANCELLED DRIVER] Batch % / %', b, batches;
    1216             END LOOP;
    1217 
    1218         -- ===========================================================
    1219         --  FLOW 4: CANCELLED BY ADMIN
    1220         --  Poraki: 1→9
    1221         --  Vreminja: request→request (momentalno)
    1222         -- ===========================================================
    1223         FOR b IN 1..batches LOOP
    1224                 INSERT INTO Notifications (message_id, sent_time, user_id, ride_id, status_id)
    1225                 SELECT * FROM (
    1226 
    1227                                   -- Poraka 1: Baranjeto isprateno → request_time
    1228                                   SELECT mid_1, r.request_time, r.user_id, r.ride_id, sid_notif_sent
    1229                                   FROM Rides r
    1230                                            JOIN Cancellations c ON r.ride_id = c.ride_id AND c.cancelled_by_type = 'ADMIN'
    1231                                   WHERE r.ride_id BETWEEN (b-1)*batch_size+1 AND b*batch_size
    1232                                     AND r.status_id = rid_cancelled
    1233 
    1234                                   UNION ALL
    1235 
    1236                                   -- Poraka 9: Nema dostapni vozaci → request_time (vednas)
    1237                                   SELECT mid_9, r.request_time, r.user_id, r.ride_id, sid_notif_fail
    1238                                   FROM Rides r
    1239 
     1024    DECLARE
     1025        batch_size INT := 500000;
     1026        b          INT;
     1027        max_ride   INT;
     1028        batches    INT;
     1029
     1030        mid_1 INT; mid_2 INT; mid_3 INT; mid_4 INT;
     1031        mid_5 INT; mid_6 INT; mid_7 INT; mid_8 INT; mid_9 INT;
     1032
     1033        sid_notif_sent   INT;
     1034        sid_notif_fail   INT;
     1035
     1036        rid_completed   INT;
     1037        rid_cancelled   INT;
     1038        rid_in_progress INT;
     1039        rid_accepted    INT;
     1040        rid_requested   INT;
     1041
     1042        pay_completed INT;
     1043        pay_failed    INT;
     1044    BEGIN
     1045        -- Message IDs
     1046        SELECT message_id INTO mid_1 FROM Messages WHERE message_text LIKE 'Vaseto baranje e uspesno%'                LIMIT 1;
     1047        SELECT message_id INTO mid_2 FROM Messages WHERE message_text LIKE 'Vozacot go prifati%'                      LIMIT 1;
     1048        SELECT message_id INTO mid_3 FROM Messages WHERE message_text LIKE 'Vozacot go odbi%'                         LIMIT 1;
     1049        SELECT message_id INTO mid_4 FROM Messages WHERE message_text LIKE 'Vozacot pristigna%'                       LIMIT 1;
     1050        SELECT message_id INTO mid_5 FROM Messages WHERE message_text LIKE 'Vozenjeto e otkazano od strana na vozac%' LIMIT 1;
     1051        SELECT message_id INTO mid_6 FROM Messages WHERE message_text LIKE 'Vozenjeto e otkazano od vasa%'            LIMIT 1;
     1052        SELECT message_id INTO mid_7 FROM Messages WHERE message_text LIKE 'Plakjanjeto e uspesno%'                   LIMIT 1;
     1053        SELECT message_id INTO mid_8 FROM Messages WHERE message_text LIKE 'Plakjanjeto ne uspea%'                    LIMIT 1;
     1054        SELECT message_id INTO mid_9 FROM Messages WHERE message_text LIKE 'Nemate dostapni%'                         LIMIT 1;
     1055
     1056        -- Notification statusi (koristime ride status kako proxy za sent/fail)
     1057        SELECT status_id INTO sid_notif_sent FROM Status WHERE status_tip='ride' AND status_text='completed' LIMIT 1;
     1058        SELECT status_id INTO sid_notif_fail FROM Status WHERE status_tip='ride' AND status_text='cancelled' LIMIT 1;
     1059
     1060        -- Ride statusi
     1061        SELECT status_id INTO rid_completed   FROM Status WHERE status_tip='ride' AND status_text='completed'   LIMIT 1;
     1062        SELECT status_id INTO rid_cancelled   FROM Status WHERE status_tip='ride' AND status_text='cancelled'   LIMIT 1;
     1063        SELECT status_id INTO rid_in_progress FROM Status WHERE status_tip='ride' AND status_text='in_progress' LIMIT 1;
     1064        SELECT status_id INTO rid_accepted    FROM Status WHERE status_tip='ride' AND status_text='accepted'    LIMIT 1;
     1065        SELECT status_id INTO rid_requested   FROM Status WHERE status_tip='ride' AND status_text='requested'   LIMIT 1;
     1066
     1067        -- Payment statusi
     1068        SELECT status_id INTO pay_completed FROM Status WHERE status_tip='payment' AND status_text='completed' LIMIT 1;
     1069        SELECT status_id INTO pay_failed    FROM Status WHERE status_tip='payment' AND status_text='failed'    LIMIT 1;
     1070
     1071        SELECT MAX(ride_id) INTO max_ride FROM Rides;
     1072        batches := CEIL(max_ride::numeric / batch_size);
     1073
     1074        RAISE NOTICE 'Pocnuvame so % batches po % rides', batches, batch_size;
     1075
     1076        -- ===========================================================
     1077        --  FLOW 1: COMPLETED rides
     1078        --  Poraki: 1→2→4→7
     1079        --  Vreminja: request→pickup→start→end+2min
     1080        -- ===========================================================
     1081        FOR b IN 1..batches LOOP
     1082                INSERT INTO Notifications (message_id, sent_time, user_id, ride_id, status_id)
     1083                SELECT * FROM (
     1084
     1085                                  -- Poraka 1: Baranjeto e uspesno isprateno → request_time
     1086                                  SELECT mid_1, r.request_time, r.user_id, r.ride_id, sid_notif_sent
     1087                                  FROM Rides r
     1088                                  WHERE r.ride_id BETWEEN (b-1)*batch_size+1 AND b*batch_size
     1089                                    AND r.status_id = rid_completed
     1090
     1091                                  UNION ALL
     1092
     1093                                  -- Poraka 2: Vozacot go prifati → pickup_time
     1094                                  SELECT mid_2, r.pickup_time, r.user_id, r.ride_id, sid_notif_sent
     1095                                  FROM Rides r
     1096                                  WHERE r.ride_id BETWEEN (b-1)*batch_size+1 AND b*batch_size
     1097                                    AND r.status_id = rid_completed
     1098
     1099                                  UNION ALL
     1100
     1101                                  -- Poraka 4: Vozacot pristigna → start_time
     1102                                  SELECT mid_4, r.start_time, r.user_id, r.ride_id, sid_notif_sent
     1103                                  FROM Rides r
     1104                                  WHERE r.ride_id BETWEEN (b-1)*batch_size+1 AND b*batch_size
     1105                                    AND r.status_id = rid_completed
     1106
     1107                                  UNION ALL
     1108
     1109                                  -- Poraka 7: Plakjanjeto uspesno → end_time + 2..5 min
     1110                                  SELECT mid_7,
     1111                                         r.end_time + (2 + floor(random()*4)) * interval '1 minute',
     1112                                         r.user_id, r.ride_id, sid_notif_sent
     1113                                  FROM Rides r
     1114                                           JOIN Payments p ON r.ride_id = p.ride_id AND p.status_id = pay_completed
     1115                                  WHERE r.ride_id BETWEEN (b-1)*batch_size+1 AND b*batch_size
     1116                                    AND r.status_id = rid_completed
     1117
     1118                              ) flows;
     1119
     1120                RAISE NOTICE '[COMPLETED] Batch % / %', b, batches;
     1121            END LOOP;
     1122
     1123        -- ===========================================================
     1124        --  FLOW 2: CANCELLED BY USER
     1125        --  Poraki: 1→6→8
     1126        --  Vreminja: request→request+1..10min→end+2min
     1127        -- ===========================================================
     1128        FOR b IN 1..batches LOOP
     1129                INSERT INTO Notifications (message_id, sent_time, user_id, ride_id, status_id)
     1130                SELECT * FROM (
     1131
     1132                                  -- Poraka 1: Baranjeto isprateno → request_time
     1133                                  SELECT mid_1, r.request_time, r.user_id, r.ride_id, sid_notif_sent
     1134                                  FROM Rides r
     1135                                           JOIN Cancellations c ON r.ride_id = c.ride_id AND c.cancelled_by_type = 'USER'
     1136                                  WHERE r.ride_id BETWEEN (b-1)*batch_size+1 AND b*batch_size
     1137                                    AND r.status_id = rid_cancelled
     1138
     1139                                  UNION ALL
     1140
     1141                                  -- Poraka 6: Otkazano od vasa strana → request_time + 1..10 min
     1142                                  SELECT mid_6,
     1143                                         r.request_time + (1 + floor(random()*10)) * interval '1 minute',
     1144                                         r.user_id, r.ride_id, sid_notif_fail
     1145                                  FROM Rides r
     1146                                           JOIN Cancellations c ON r.ride_id = c.ride_id AND c.cancelled_by_type = 'USER'
     1147                                  WHERE r.ride_id BETWEEN (b-1)*batch_size+1 AND b*batch_size
     1148                                    AND r.status_id = rid_cancelled
     1149
     1150                                  UNION ALL
     1151
     1152                                  -- Poraka 8: Plakjanjeto ne uspea → end_time + 2..5 min
     1153                                  SELECT mid_8,
     1154                                         r.end_time + (2 + floor(random()*4)) * interval '1 minute',
     1155                                         r.user_id, r.ride_id, sid_notif_fail
     1156                                  FROM Rides r
     1157                                           JOIN Payments p ON r.ride_id = p.ride_id AND p.status_id = pay_failed
     1158                                           JOIN Cancellations c ON r.ride_id = c.ride_id AND c.cancelled_by_type = 'USER'
     1159                                  WHERE r.ride_id BETWEEN (b-1)*batch_size+1 AND b*batch_size
     1160                                    AND r.status_id = rid_cancelled
     1161
     1162                              ) flows;
     1163
     1164                RAISE NOTICE '[CANCELLED USER] Batch % / %', b, batches;
     1165            END LOOP;
     1166
     1167        -- ===========================================================
     1168        --  FLOW 3: CANCELLED BY DRIVER
     1169        --  Poraki: 1→2→5
     1170        --  Vreminja: request→pickup→request+5..15min
     1171        -- ===========================================================
     1172        FOR b IN 1..batches LOOP
     1173                INSERT INTO Notifications (message_id, sent_time, user_id, ride_id, status_id)
     1174                SELECT * FROM (
     1175
     1176                                  -- Poraka 1: Baranjeto isprateno → request_time
     1177                                  SELECT mid_1, r.request_time, r.user_id, r.ride_id, sid_notif_sent
     1178                                  FROM Rides r
     1179                                           JOIN Cancellations c ON r.ride_id = c.ride_id AND c.cancelled_by_type = 'DRIVER'
     1180                                  WHERE r.ride_id BETWEEN (b-1)*batch_size+1 AND b*batch_size
     1181                                    AND r.status_id = rid_cancelled
     1182
     1183                                  UNION ALL
     1184
     1185                                  -- Poraka 2: Vozacot prifati → pickup_time
     1186                                  SELECT mid_2, r.pickup_time, r.user_id, r.ride_id, sid_notif_sent
     1187                                  FROM Rides r
     1188                                           JOIN Cancellations c ON r.ride_id = c.ride_id AND c.cancelled_by_type = 'DRIVER'
     1189                                  WHERE r.ride_id BETWEEN (b-1)*batch_size+1 AND b*batch_size
     1190                                    AND r.status_id = rid_cancelled
     1191
     1192                                  UNION ALL
     1193
     1194                                  -- Poraka 5: Otkazano od vozac → request_time + 5..15 min
     1195                                  SELECT mid_5,
     1196                                         r.request_time + (5 + floor(random()*11)) * interval '1 minute',
     1197                                         r.user_id, r.ride_id, sid_notif_fail
     1198                                  FROM Rides r
     1199                                           JOIN Cancellations c ON r.ride_id = c.ride_id AND c.cancelled_by_type = 'DRIVER'
     1200                                  WHERE r.ride_id BETWEEN (b-1)*batch_size+1 AND b*batch_size
     1201                                    AND r.status_id = rid_cancelled
     1202
     1203                              ) flows;
     1204
     1205                RAISE NOTICE '[CANCELLED DRIVER] Batch % / %', b, batches;
     1206            END LOOP;
     1207
     1208        -- ===========================================================
     1209        --  FLOW 4: CANCELLED BY ADMIN
     1210        --  Poraki: 1→9
     1211        --  Vreminja: request→request (momentalno)
     1212        -- ===========================================================
     1213        FOR b IN 1..batches LOOP
     1214                INSERT INTO Notifications (message_id, sent_time, user_id, ride_id, status_id)
     1215                SELECT * FROM (
     1216
     1217                                  -- Poraka 1: Baranjeto isprateno → request_time
     1218                                  SELECT mid_1, r.request_time, r.user_id, r.ride_id, sid_notif_sent
     1219                                  FROM Rides r
     1220                                           JOIN Cancellations c ON r.ride_id = c.ride_id AND c.cancelled_by_type = 'ADMIN'
     1221                                  WHERE r.ride_id BETWEEN (b-1)*batch_size+1 AND b*batch_size
     1222                                    AND r.status_id = rid_cancelled
     1223
     1224                                  UNION ALL
     1225
     1226                                  -- Poraka 9: Nema dostapni vozaci → request_time (vednas)
     1227                                  SELECT mid_9, r.request_time, r.user_id, r.ride_id, sid_notif_fail
     1228                                  FROM Rides r
     1229                                           JOIN Cancellations c ON r.ride_id = c.ride_id AND c.cancelled_by_type = 'ADMIN'
     1230                                  WHERE r.ride_id BETWEEN (b-1)*batch_size+1 AND b*batch_size
     1231                                    AND r.status_id = rid_cancelled
     1232
     1233                              ) flows;
     1234
     1235                RAISE NOTICE '[CANCELLED ADMIN] Batch % / %', b, batches;
     1236            END LOOP;
     1237
     1238        RAISE NOTICE '*** GOTOVO: SITE NOTIFICATIONS SE GENERIRANI ***';
     1239    END $$;
    12401240```