SQL Server: ако записът е намерен, актуализация, друго вмъкване, корекция на грешки в заявка за сливане

Измислих следната заявка за SQL Server за актуализиране на ред, ако се намери друго вмъкване

merge tblpermissions  as t
using (select cid, uid from tblpermissions) as s
on (t.cid = s.cid and t.uid=s.uid)
when not matched
THEN INSERT (cid, uid, [read], [write], [readonly], [modify], [admin]) VALUES ('1',   '1', 1, 1, 0, 1, 1) 
when matched 
THEN UPDATE SET [read]=1, write=1, readonly=0, modify=1, admin=1 ;

Въпреки че не извежда никаква грешка, не постига това, което очаквам. няма запис в таблицата и не се вмъква нов запис.

Някаква корекция?

Редактиране: Имайки предвид вашите предложения, го модифицирах допълнително, както е показано по-долу, но без очакван резултат -

MERGE INTO tblpermissions  as t
using (SELECT '1' AS cid, '1' AS uid FROM tblpermissions) as s
on (t.cid = s.cid and t.uid=s.uid)
WHEN NOT MATCHED 
THEN INSERT (cid, uid, [read], [write], [readonly], [modify], [admin])
VALUES  ('1', '1', 1, 1, 0, 1, 1) 
WHEN MATCHED
THEN UPDATE SET [read]=1, write=1, readonly=0, modify=1, admin=1 ;

Редактиране: моля, проверете коментара в долната част, по-долу е подобрената заявка за вашите предложения, да не говорим, че няма да работи според очакванията, тъй като отново приема същата таблица.

MERGE INTO tblpermissions  as t
using tblpermissions as s
on (t.cid = s.cid and t.uid=s.uid)
WHEN NOT MATCHED 
THEN INSERT (cid, uid, [read], [write], [readonly], [modify], [admin])
VALUES  ('1', '1', 1, 1, 0, 0, 1) 
WHEN MATCHED
THEN UPDATE SET [read]=1, write=1, readonly=0, modify=1, admin=1 ;

Редактиране: изберете-ако бъде намерена актуализация-друго вмъкнете алтернатива по-долу -

$query = "SELECT * FROM ".SQL_PREFIX."permissions\n"
              ."WHERE cid='".$cid."' AND uid='".$uid."'";
    $sth = $this->dbh->query($query);
    $res = $sth->fetch();
    //print_r($res);var_dump($res);
    if(!$res || $res==null)
    {
        $query = "INSERT INTO ".SQL_PREFIX."permissions (cid, uid, [read], [write], [readonly], [modify], [admin])\n"
            ."VALUES ('$cid', '$uid', ".implode(", ", $values).")";
        if(!($sth = $this->dbh->query($query)))
            $this->db_error(__('Error inserting user permissions.'),
                $query);
    }else{
        $query = "UPDATE ".SQL_PREFIX."permissions SET ".implode(", ", $sets).";";
        if(!($sth = $this->dbh->query($query)))
            $this->db_error(__('Error updating user permissions.'),
                $query);
    } 

Редактиране: По-долу е mysql решението за тази ситуация -

ВМЪКНЕТЕ в tblpermissions (cid, uid, [read], [write], [readonly], [modify], [admin]) СТОЙНОСТИ ('1', '1', 1, 1, 0, 0, 1) НА ДУБЛИКАТ КЛЮЧОВА АКТУАЛИЗАЦИЯ [четене]=1, запис=1, само за четене=0, модифициране=1, администратор=1

който просто използва ключовата дума DUPLICATE KEY. Също така бих искал отново да подчертая, че има уникално ключово ограничение за комбинацията cid & uid. И така, това, което mysql прави, е, че първо просто търси комбинацията от cid & uid, която се опитваме да вмъкнем, ако намери актуализации, иначе вмъква нов запис.


person code-match    schedule 09.05.2013    source източник
comment
Сливате се в tblPermissions, като избирате от същото tblPermissions ?!?!? Предполагам, че всички редове, избрани в s, вече ще бъдат в tblPermissions (тъй като сте ги избрали от там) - така че очевидно ще получите само частта when matched. ...   -  person marc_s    schedule 09.05.2013


Отговори (1)


Тъй като изходната и целевата таблици са еднакви, никога няма случай на несъвпадение на редове. Всички редове на tblpermissions се актуализират.

За да се вмъкне, изходната таблица (дефинирана с using) трябва да е различна от целевата таблица, като следните примери:

merge tblpermissions  as t
using (select cid, uid from otherTable) as s
on (t.cid = s.cid and t.uid = s.uid)

merge tblpermissions  as t
using (select cid, uid from tblpermissions) as s
on (t.cid = s.cid + 1 and t.uid = s.uid + 1)

Редактиране: Тъй като използвате постоянни стойности вместо резултат от избор от която и да е таблица, може би следното ще свърши работа:

merge tblpermissions as t
using (select '1' cid, '1' uid, 1 [read], 1 [write], 0 [readonly], 0 [modify], 1 [admin]) s
on (t.cid = s.cid and t.uid = s.uid)
when matched 
    then update set [read] = s.[read], write = s.[write], readonly = s.[readonly], modify = s.[modify], admin = s.[admin]
when not matched
    then insert (cid, uid, [read], [write], [readonly], [modify], [admin]) values (s.cid, s.uid, s.[read], s.[write], s.[readonly], s.[modify], s.[admin]);

Въпреки че смятам, че вмъкването само на едно обединяване на редове е прекалено, би било по-лесно да направите следното:

if exists (select 1 from tblpermissions where cid = '1' and uid = '1')
update tblpermissions set [read] = 1, write = 1, readonly = 0, modify = 1, admin = 1 where cid = '1' and uid = '1'
else
    insert tblpermissions (cid, uid, [read], [write], [readonly], [modify], [admin]) VALUES ('1', '1', 1, 1, 0, 1, 1)

Не мисля, че SQL Server има по-кратък или по-елегантен начин да извърши това, нищо като on duplicate от MySQL.

person dang    schedule 09.05.2013
comment
добре, разбирам мисълта ви, но просто искам да постигна това - ако съществува запис с определен идентификатор, тогава го актуализирайте, в противен случай вмъкнете нов запис. В този случай комбинацията cid & uid съществува, тогава актуализирайте разрешенията за тях, в противен случай вмъкнете нов запис за разрешения. - person code-match; 09.05.2013
comment
Проблемът е, че сравнявате същите комбинации от cid и uid със самите тях. Например, ако tblpermissions съдържа ред с cid = 1 & uid = 1, тогава той ще бъде сравнен със същия ред с cid = 1 & uid = 1 , и същото важи за всеки ред на масата. В крайна сметка не може да има определен идентификатор, който да не съществува, защото сравнявате едни и същи идентификатори със самите тях. - person dang; 09.05.2013
comment
добре, така ли е, че „using(some query) as s“ дефинира източника, за да го сравни с целевата таблица. - person code-match; 10.05.2013
comment
@jhackspmarrow Точно така. Всъщност не е задължително да е заявка, можете да използвате директно таблица, като например using otherTable on a = b. - person dang; 10.05.2013
comment
@jhackspmarrow Намерихте ли отговор на този въпрос? Ако е това, което предложих, можете ли да го маркирате като правилно? Или пък ме уведомете как отговорът ми може да бъде подобрен или може би дори да публикувате свой различен отговор и да го маркирате като правилен. - person dang; 13.05.2013
comment
all n @dang съжалявам за забавения отговор. Уебсайтът на ms обяснява синтаксиса за сливане на technet.microsoft.com/en-us/library/ Разбрах го и от вашите коментари също, че очаква „другата таблица“ в клаузата за използване, но за съжаление това не е това, което търся. Трябва да направя тази операция на „същата маса“. Досега не можах да измисля по-добро решение, освен традиционния начин първо да изберете запис - ако бъде намерен, актуализирайте и в противен случай вмъкнете. - person code-match; 15.05.2013
comment
@jhackspmarrow Можете да обедините една и съща таблица сама по себе си напълно добре, просто трябва да зададете условието за сливане на нещо, което позволява различни редове да корелират. Ако cid и uid са PK за тази таблица, не можете да имате различен набор в източника и целта. Можете ли да публикувате своя код, за да изберете първо записи и след това да решите какво да правите? Може би можем да помогнем да го превърнем в сливане. - person dang; 15.05.2013
comment
съжалявам отново @dang за късния отговор, редактирах въпроса, моля, намерете алтернативата select-n-update по-горе. - person code-match; 20.05.2013
comment
Изглежда, че стойностите за cid и uid не идват от таблицата, а от някои PHP променливи. Ако случаят е такъв, предполагам, че не може да се превърне в сливане, тъй като сравнението изисква данни, които не присъстват изключително от SQL заявки. - person dang; 20.05.2013
comment
добре, но ще продължа да мисля за това. mysql има свой собствен начин да се справи с такава ситуация, чудя се защо mssql не може да го предостави. - person code-match; 22.05.2013
comment
Какво е решението на MySQL за това? Може би можем да измислим нещо подобно в SQL Server. - person dang; 22.05.2013
comment
Добре @Dang, благодаря ти, че все още проявяваш интерес. включи MySQL решение по-горе и се опитваше да намери еквивалент на MS SQL за същото. - person code-match; 24.05.2013