Index: .idea/sqldialects.xml
===================================================================
--- .idea/sqldialects.xml	(revision e1895286354e8450ee9d57754ab5b33e19b1ae94)
+++ .idea/sqldialects.xml	(revision 9715b0adfad80b65727cd1cf315914035f034335)
@@ -2,5 +2,5 @@
 <project version="4">
   <component name="SqlDialectMappings">
-    <file url="file://$PROJECT_DIR$/music/constrains/constrains.sql" dialect="PostgreSQL" />
+    <file url="file://$PROJECT_DIR$/music/constrains/general_constrains.sql" dialect="PostgreSQL" />
     <file url="file://$PROJECT_DIR$/music/constrains/soft_delete.sql" dialect="PostgreSQL" />
     <file url="file://$PROJECT_DIR$/music/procedures/insert_track_with_price.sql" dialect="PostgreSQL" />
Index: music/constrains/soft_delete.sql
===================================================================
--- music/constrains/soft_delete.sql	(revision e1895286354e8450ee9d57754ab5b33e19b1ae94)
+++ music/constrains/soft_delete.sql	(revision 9715b0adfad80b65727cd1cf315914035f034335)
@@ -18,4 +18,5 @@
 DECLARE
     r RECORD;
+    pk_col TEXT;
 BEGIN
     FOR r IN (
@@ -23,16 +24,32 @@
         FROM information_schema.tables
         WHERE table_schema = 'public'
-        AND table_type = 'BASE TABLE'
+          AND table_type = 'BASE TABLE'
     )
     LOOP
+        SELECT kcu.column_name INTO pk_col
+        FROM information_schema.table_constraints tc
+        JOIN information_schema.key_column_usage kcu
+          ON tc.constraint_name = kcu.constraint_name
+         AND tc.table_name = kcu.table_name
+        WHERE tc.constraint_type = 'PRIMARY KEY'
+          AND tc.table_name = r.table_name
+        LIMIT 1;
+
+        IF pk_col IS NULL THEN
+            RAISE NOTICE 'Table % has no primary key, skipping soft delete trigger', r.table_name;
+            CONTINUE;
+        END IF;
+
+        EXECUTE format('ALTER TABLE public.%I ADD COLUMN IF NOT EXISTS deleted_at TIMESTAMP;', r.table_name);
+
         EXECUTE format(
             'CREATE OR REPLACE FUNCTION soft_delete_%I()
              RETURNS TRIGGER AS $func$
              BEGIN
-                 UPDATE %I SET deleted_at = NOW() WHERE ctid = OLD.ctid;
+                 UPDATE %I SET deleted_at = NOW() WHERE %I = OLD.%I;
                  RETURN NULL;
              END;
              $func$ LANGUAGE plpgsql;',
-            r.table_name, r.table_name
+            r.table_name, r.table_name, r.table_name, pk_col
         );
 
