führen sie ein skript mit sqlplus aus, das leerzeichen, semikolons und schrägstriche enthält
<p>gelegentlich erhalte ich ein skript, das in sql developer oder toad einwandfrei ausgeführt wird, jedoch änderungen erfordert, um erfolgreich in sql * plus ausgeführt zu werden. hier ist ein worst-case-beispiel mit mehreren anweisungen mit leerzeilen, semikolons und schrägstrichen:</p><pre><code>insert into t1 values ('a ; / '); insert into t1 values ('b ; / '); delete from t1 where c1 = 'c ; / '; </code></pre><p>aus verschiedenen gründen müssen diese anweisungen in sql * plus ausgeführt werden. die leeren zeilen lassen sich leicht mit einem einfachen ...</p><pre><code>set sqlblanklines on </code></pre><p>mir ist bekannt, dass <code>sqlterminator</code> geändert und/oder deaktiviert werden kann, aber beide würden änderungen am code erfordern. ersteres verschiebt das problem, ohne es zu lösen, und behebt auch nicht das problem mit eingebetteten schrägstrichen.</p><p>die beste antwort wäre eine möglichkeit, diese anweisungen ohne änderung ausführen zu lassen, indem die umgebung auf irgendeine weise geändert wird (wie dies bei sqlblanklines der fall ist). wenn dies nicht möglich ist, gibt es möglicherweise eine möglichkeit, die skripte programmgesteuert zu ändern. ich versuche, manuelle änderungen zu vermeiden.</p>
<p>sie können das meiste davon tun, indem sie eine login.sql verwenden. login.sql wird während der - überraschenden - anmeldung ausgeführt und aus ihrem sqlpath oder dem aktuellen verzeichnis geladen. für die beispiele, die sie gegeben haben, haben sie wirklich den schlimmsten fall gewählt.</p><p>problem ist der sqlterminator. was auch immer sie dort eingeben, der schrägstrich wird als kostenloser sql-minator beibehalten. daneben sucht sqlplus zuerst nach dem sqlterminator und führt dies vor dem scannen zum string-terminator durch. ein fehler, wenn sie mich fragen. der schrägstrich kann in einer zeichenfolge verwendet werden, solange er nicht allein in einer separaten zeile steht. sobald sqlplus das als sqlterminator angegebene zeichen findet, ignoriert es alles andere und hört auf zu lesen.</p><p>der schrägstrich kann behandelt werden, solange er nicht alleine in einer zeile steht.</p><p>login.sql enthält:</p><pre><code>prompt run login.sql show sqlterminator show sqlblanklines set sqlblanklines on set sqlterminator ';' show sqlterminator show sqlblanklines prompt ready login.sql set echo on </code></pre><p>leigh.sql enthält:</p><pre><code>insert into t1 values ('fail bc semicolon a;a / '); insert into t1 values ('fail bc solo / aa / '); insert into t1 values ('ok / not solo aa /a '); delete from t1 where a = 'c a/ '; </code></pre><p>führen sie das skript aus:</p><pre><code>sqlplus leigh/leigh@orcl @leigh sql*plus: release 10.2.0.4.0 - production on thu aug 9 22:36:20 2012 copyright (c) 1982, 2007, oracle. all rights reserved. connected to: oracle database 11g enterprise edition release 11.2.0.3.0 - 64bit production with the partitioning, real application clusters, automatic storage management, olap, data mining and real application testing options run login.sql sqlterminator ";" (hex 3b) sqlblanklines off sqlterminator ";" (hex 3b) sqlblanklines on ready login.sql sql&gt; insert into t1 values ('fail bc semicolon 2 a;a 3 / error: ora-01756: quoted string not properly terminated sql&gt; '); sp2-0042: unknown command "')" - rest of line ignored. sql&gt; sql&gt; insert into t1 values ('fail bc solo / 2 3 4 aa 5 / error: ora-01756: quoted string not properly terminated sql&gt; '); sp2-0042: unknown command "')" - rest of line ignored. sql&gt; sql&gt; insert into t1 values ('ok / not solo 2 3 4 aa 5 /a 6 '); 1 row created. sql&gt; sql&gt; delete from t1 where a = 'c 2 3 4 a/ 5 '; 0 rows deleted. </code></pre><p>sie müssen nicht mit start-/endblöcken herumspielen. der befehl sqlterminator innerhalb des befehls kann nicht verarbeitet werden, unabhängig davon, wo er sich in einer zeichenfolge befindet oder nicht. er kann keine zeilen mit schrägstrich allein in einer zeile in einer zeichenfolge verarbeiten.</p>
<p>die tastaturkombination, nach der sie suchen (<kbd>ctrl</kbd>+<kbd>k</kbd>, <kbd>ctrl</kbd>+<kbd>d</kbd>) dient der "formatierung" - aber nicht in dem maße, wie sie es zu erwarten scheinen. es ist kein prettifier, sondern dient nur zum einfügen korrekter abstände und tabulatoren wie in <code>tools &gt; options &gt; text editor &gt; transact-sql &gt; general/tabs</code>. wenn sie also einen teil des texts markieren und die tastaturkombination drücken, werden tabulatoren in 4 leerzeichen konvertiert ( wenn sie leerzeichen einfügen ausgewählt haben, wenden sie die von ihnen angegebene art des einrückens usw. an.</p><p>diese option soll den code nicht lesbarer machen. dies ist keine funktionalität, die management studio derzeit nativ bietet. es gibt zwar mehrere optionen von drittanbietern - einige befinden sich außerhalb von management studio, z.</p><ul> <li> <a href="http://extras.sqlservercentral.com/prettifier/prettifier.aspx">sql prettifier von simple-talk</a> </li> <li> <a href="http://poorsql.com/">schlechtes sql</a> (welches <a href="https://dba.stackexchange.com/a/45052/1186">thomas schlug vor</a> )</li> </ul><p>außerdem gibt es add-ins für verschiedene ebenen der formatierungsunterstützung im editor:</p><ul> <li> <a href="http://www.red-gate.com/products/sql-development/sql-prompt/features">sql-eingabeaufforderung von red-gate</a> </li> <li> <a href="http://ssmstoolspack.com/features?f=4">ssms tools pack</a> </li> <li> <a href="http://www.apexsql.com/sql\_tools\_refactor.aspx">apexsqls refactor</a> </li> <li> <a href="http://www.ssmsboost.com/features/ssms-add-in-format-sql-document">ssmsboost</a> </li> <li> <a href="http://www.devart.com/dbforge/sql/sqlcomplete/">dbforge sql complete</a> (welches <a href="https://dba.stackexchange.com/a/45063/1186">robert schlug vor</a> )</li> </ul><p>nun, der grund, warum sie die nachricht erhalten ...</p><blockquote> <p>die tastenkombination (strg + k, strg + d) ist an den befehl (format format) gebunden, der derzeit nicht verfügbar ist.</p> </blockquote><p>... liegt daran, dass ssms diese tastenkombination einem anderen kontext zugeordnet hat. die art und weise, wie sie <em> sollten</em> in der lage sein, dies zu "beheben" - auch hier würde es immer noch nicht das tun, was sie möchten, selbst wenn das "beheben" funktioniert - ist wie folgt:</p><ol> <li>gehe zu <code>tools &gt; options &gt; environment &gt; keyboard</code></li> <li>platzieren sie ihren cursor in das feld <code>press shortcut keys:</code></li> <li>schlagen <kbd>ctrl</kbd>+<kbd>k</kbd>, <kbd>ctrl</kbd>+<kbd>d</kbd></li> <li> <p>ändern sie das dropdown-menü <code>shortcut currently used by:</code> von <code>datawarehouse designer</code> in <code>text editor</code>.</p> <p><img src="https://i.stack.imgur.com/1g5oe.png" alt="enter image description here"></p> </li> <li> <p>drücke ok</p> </li> </ol><p>dies ist <em> angenommen</em>, um die tastaturkombination dem texteditor zuzuordnen, aber management studio setzt sie zurück, nachdem sie auf ok geklickt haben (sie erhalten weiterhin die fehlermeldung. ich denke, das problem ist das die dokumentation geht davon aus, dass diese funktionalität vorhanden ist, aber management studio weiß es besser und bietet sie einfach nicht an (und microsoft wird dies wahrscheinlich als fehler in der dokumentation abschreiben und korrigieren, anstatt als mangel im tool) hoffe in der zukunft, aber vorerst <a href="http://connect.microsoft.com/sql/feedback/viewfeedback.aspx?feedbackid=496617">dies ist ein bekanntes und weitgehend ignoriertes problem</a> . sie werden feststellen, dass die registerkarte <code>formatting</code> diese <a href="http://msdn.microsoft.com/en-us/library/ms174205(sql.110).aspx">die dokumentation bezieht sich auf</a> ist einfach nicht vorhanden (obwohl es für xml vorhanden ist, wo die tastaturkombination funktioniert). in der dokumentation sollte wahrscheinlich folgendes angegeben werden:</p><blockquote> <p>wendet die einrückungs- und leerzeichenformatierung für die sprache an, die im bereich <strong> formatierung </strong> der sprache im texteditor <strong> angegeben ist </strong> abschnitt des dialogfelds <strong> optionen </strong>. nur im texteditor verfügbar <strong> <em> und nur für bestimmte sprachen</em> </strong>.</p> </blockquote><p>eine andere möglichkeit, sich ein bild davon zu machen, welche art von formatierungsoptionen ssms nativ bietet, besteht darin, unter <code>tools &gt; customize &gt; commands &gt; edit &gt; add command... &gt; format</code> die liste der möglichen befehle dort anzuzeigen. nichts, was darauf hinweist, dass kenntnisse der tatsächlichen sprache vorhanden sind, sodass nicht bekannt ist, wo zeilenumbrüche eingefügt oder zusätzliche einrückungen hinzugefügt oder klammern usw. verwendet werden sollen.</p><p><img src="https://i.stack.imgur.com/zhrer.png" alt="enter image description here"></p><p>wenn sie eine sprachspezifische formatierung wünschen, um den vorhandenen t-sql-code besser lesbar zu machen, erhalten sie von ssms nicht viel, und sie müssen nach anderen optionen suchen.</p> <p>row\_number () ist eine ranking-fensterfunktion, und ranking-fensterfunktionen erfordern eine obligatorische order by-klausel. wenn sie versuchen, es ohne order by zu schreiben, wird ein syntaxfehler angezeigt.</p><pre><code>select row\_number() over() from (values ('a'), ('b'), ('c')) as x(y); -- msg 4112, level 15, state 1, line 1 -- the function 'row\_number' must have an over clause with order by. </code></pre><p>der trick mit der unterabfrage wurde von jemandem entdeckt, der darüber als leistungsoptimierung gebloggt hat. sql server führt immer eine sortieroperation aus, da konstanten für die order by-klausel nicht zulässig sind:</p><pre><code>select row\_number() over(order by null) from (values ('a'), ('b'), ('c')) as x(y); -- msg 5309, level 16, state 1, line 1 -- windowed functions, aggregates and next value for functions -- do not support constants as order by clause expressions. </code></pre><p>und ganzzahlen, die als indizes behandelt werden, sind es auch nicht:</p><pre><code>select row\_number() over(order by 1) from (values ('a'), ('b'), ('c')) as x(y); -- msg 5308, level 16, state 1, line 1 -- windowed functions, aggregates and next value for functions -- do not support integer indices as order by clause expressions. </code></pre><p>es stellt sich heraus, dass sie diese einschränkung aufgrund eines fehlers im code umgehen können, indem sie eine unterabfrage verwenden, die aus irgendeinem grund zulässig ist, und den sortieroperator entfernen.</p><pre><code>select row\_number() over(order by (select 1)) from (values ('a'), ('b'), ('c')) as x(y); </code></pre><p> <a href="https://i.stack.imgur.com/i76qa.png">(<img src="https://i.stack.imgur.com/i76qa.png" alt="no sort operator"></a> </p><p>sie können eine beliebige konstante in der unterabfrage verwenden. null erinnert wahrscheinlich an die gewohnheit, select null in exists-prädikaten zu verwenden, die in der frühen geschichte von sql server einen leistungseinfluss im gegensatz zu * oder einem anderen spaltenausdruck hatten der optimierer war nicht klug genug, um ihn zu ignorieren.</p><p>hth</p><p><strong> [~ # ~] update [~ # ~] </strong> @ erik-darling kommentierte, dass sie es auch umgehen können, indem sie berechnete ausdrücke verwenden:</p><pre><code>you can do select row\_number() over (order by 1/0); </code></pre> <p>sie sollten versuchen, schleifen generell zu vermeiden. sie sind normalerweise weniger effizient als satzbasierte lösungen und weniger lesbar.</p><p>das folgende sollte ziemlich effizient sein.</p><p>dies gilt umso mehr, wenn die spalten name und weight im index <code>include-</code> d sein könnten, um die schlüsselsuche zu vermeiden.</p><p>es kann den eindeutigen index in der reihenfolge <code>turn</code> scannen und die laufende summe der spalte <code>weight</code> berechnen. verwenden sie dann <code>lead</code> mit denselben ordnungskriterien, um die laufende summe zu ermitteln die nächste reihe wird sein.</p><p>sobald die erste zeile gefunden wird, in der diese 1000 überschreitet oder <code>null</code> ist (was anzeigt, dass keine nächste zeile vorhanden ist), kann der scan gestoppt werden.</p><pre><code>with t1 as (select *, sum(weight) over (order by turn rows unbounded preceding) as cume\_weight from [dbo].[line]), t2 as (select lead(cume\_weight) over (order by turn) as next\_cume\_weight, * from t1) select top 1 name from t2 where next\_cume\_weight &gt; 1000 or next\_cume\_weight is null order by turn </code></pre><h1>ausführungsplan</h1><p> <a href="https://i.stack.imgur.com/gb1mw.png">(<img src="https://i.stack.imgur.com/gb1mw.png" alt="enter image description here"></a> </p><p>in der praxis scheint es ein paar zeilen vor dem unbedingt erforderlichen zu lesen - es sieht so aus, als würde jedes fenster-spool/stream-aggregat-paar zwei zusätzliche zeilen lesen.</p><p>für die beispieldaten in der frage müssten im idealfall nur zwei zeilen aus dem index-scan gelesen werden, in wirklichkeit werden jedoch 6 zeilen gelesen. dies ist jedoch kein wesentliches effizienzproblem und verschlechtert sich nicht, wenn der tabelle weitere zeilen hinzugefügt werden (wie in) <a href="https://dbfiddle.uk/?rdbms=sqlserver\_2017&amp;fiddle=892e6bb7c1af912413b01d05e606a98a">diese demo</a> )</p><p>für diejenigen, die an dieser ausgabe interessiert sind, wird unten ein bild mit den von jedem operator ausgegebenen zeilen (wie durch das erweiterte ereignis <code>query\_trace\_column\_values</code> gezeigt) angezeigt. die zeilen werden in der reihenfolge <code>row\_id</code> ausgegeben (beginnend mit <code>47</code> für die erste zeile, die vom index-scan gelesen wurde und bei <code>113</code> für <code>top</code> endet)</p><p>klicken sie auf das bild unten, um es zu vergrößern, oder sehen sie alternativ <a href="https://imgur.com/a/c7npqqh">die animierte version, um den ablauf einfacher zu verfolgen</a> .</p><p>anhalten der animation an dem punkt, an dem das rechte stream-aggregat seine erste zeile ausgegeben hat (für gary - turn = 1). es scheint offensichtlich, dass es darauf gewartet hat, seine erste zeile mit einem anderen windowcount zu erhalten (für jo - turn = 2). und die fensterspule gibt die erste "jo" -zeile erst frei, wenn sie die nächste zeile mit einem anderen <code>turn</code> gelesen hat (für thomas - turn = 3)</p><p>die fensterspule und das stream-aggregat bewirken also, dass eine zusätzliche zeile gelesen wird, und es gibt vier davon im plan - daher 4 zusätzliche zeilen.</p><p> <a href="https://i.stack.imgur.com/cwllc.jpg">(<img src="https://i.stack.imgur.com/cwllc.jpg" alt="enter image description here"></a> </p><p>es folgt eine erläuterung der oben gezeigten spalten (basierend auf info <a href="https://www.microsoft.com/en-us/p/microsoft-sql-server-2012-high-performance-t-sql-using-window-functions/fgqpf3h0qlch">hier</a> )</p><ul> <li><strong> knotenname: index-scan, knoten-id: 15, spaltenname: id </strong> basistabellenspalte, die vom index abgedeckt wird</li> <li><strong> knotenname: index-scan, knoten-id: 15, spaltenname: drehen sie die basistabellenspalte </strong>, die vom index abgedeckt wird</li> <li><strong> nodename: clustered index seek, nodeid: 17, columnname: gewicht </strong> basistabellenspalte, die aus der suche abgerufen wurde</li> <li><strong> nodename: clustered index seek, nodeid: 17, columnname: name </strong> basistabellenspalte, die aus der suche abgerufen wurde</li> <li><strong> nodename: segment, nodeid: 13, columnname: segment1010 </strong> gibt 1 am anfang einer neuen gruppe zurück oder andernfalls null. da kein <code>partition by</code> in <code>sum</code> vorhanden ist, erhält nur die erste zeile 1</li> <li><strong> nodename: sequenzprojekt, nodeid: 12, columnname: rownumber1009 </strong> <code>row\_number()</code> innerhalb der durch das segment1010-flag angegebenen gruppe. da sich alle zeilen in derselben gruppe befinden, werden ganze zahlen von 1 bis 6 aufgestiegen. wird in fällen wie <code>rows between 5 preceding and 2 following</code> zum filtern von zeilen mit rechten rahmen verwendet. (oder wie für <code>lead</code> später)</li> <li><strong> nodename: segment, nodeid: 11, columnname: segment1011 </strong> gibt 1 am anfang einer neuen gruppe zurück oder andernfalls null. da kein <code>partition by</code> in <code>sum</code> vorhanden ist, erhält nur die erste zeile 1 (wie segment1010).</li> <li><strong> nodename: window spool, nodeid: 10, columnname: windowcount1012 </strong> attribut, das zeilen gruppiert, die zu einem fensterrahmen gehören. diese fensterspule verwendet den fall "fast track" für <code>unbounded preceding</code>. wo es zwei zeilen pro quellzeile ausgibt. eins mit den kumulativen werten und eins mit den detailwerten. obwohl es keinen sichtbaren unterschied in den durch <code>query\_trace\_column\_values</code> offenbarten zeilen gibt, gehe ich davon aus, dass kumulative spalten in der realität vorhanden sind.</li> <li><strong> nodename: stream aggregate, nodeid: 9, columnname: expr1004 </strong> <code>count(*)</code> gruppiert nach windowcount1012 gemäß plan, aber tatsächlich eine laufende anzahl</li> <li><strong> nodename: stream aggregate, nodeid: 9, columnname: expr1005 </strong> <code>sum(weight)</code> gruppiert nach windowcount1012 gemäß plan, aber tatsächlich die laufende gewichtssumme (dh <code>cume\_weight</code>)</li> <li><strong> nodename: segment, nodeid: 7, columnname: expr1002 </strong> <code>case when [expr1004]=(0) then null else [expr1005] end</code> - sehen sie nicht, wie <code>count(*)</code> kann sei 0, also läuft immer die summe (<code>cume\_weight</code>)</li> <li><strong> knotenname: segment, knoten-id: 7, spaltenname: segment1013 </strong> nein <code>partition by</code> in <code>lead</code>, sodass die erste zeile 1 erhält. alle verbleibenden werden null</li> <li><strong> nodename: sequenzprojekt, nodeid: 6, columnname: rownumber1006 </strong> <code>row\_number()</code> innerhalb der durch das segment1013-flag angegebenen gruppe. da sich alle zeilen in derselben gruppe befinden, sind dies ganze zahlen von 1 bis 4</li> <li><strong> nodename: segment, nodeid: 4, columnname: bottomrownumber1008 </strong> rownumber1006 + 1, da <code>lead</code> die nächste zeile erfordert</li> <li><strong> nodename: segment, nodeid: 4, columnname: toprownumber1007 </strong> rownumber1006 + 1, da <code>lead</code> die nächste zeile erfordert</li> <li><strong> knotenname: segment, knoten-id: 4, spaltenname: segment1014 </strong> nein <code>partition by</code> in <code>lead</code>, sodass die erste zeile 1 erhält. alle verbleibenden werden null</li> <li><strong> nodename: window spool, nodeid: 3, columnname: windowcount1015 </strong> attribut, das zeilen, die zu einem fensterrahmen gehören, unter verwendung der vorherigen zeilennummern gruppiert. der fensterrahmen für <code>lead</code> hat maximal 2 zeilen (die aktuelle und die nächste)</li> <li><strong> nodename: stream aggregate, nodeid: 2, columnname: expr1003 </strong> <code>last\_value([expr1002])</code> für <code>lead(cume\_weight)</code></li> </ul> <h2>es kommt darauf an ™</h2><p>die fähigkeit, einen oder mehrere cursor zu umgehen, hängt davon ab, was in diesem cursor ausgeführt wird. ohne zu wissen, was darin vor sich geht, gibt es keine möglichkeit zu sagen. es kann sein, dass es keine problemumgehung gibt und sie eine zeilenweise verarbeitung durchführen müssen.</p><p>nachfolgend einige beispiele.</p><h2>funktioniert nicht in sets</h2><p>dieses beispiel ist das grundlegendste und ist einfach die tatsache, dass sie ihr gesamtes dataset oder teile ihres datasets auf einmal abfragen können, aber der cursor wurde erstellt und fragt die daten zeilenweise ab. übliche, durch die dies ersetzt werden kann, sind <code>join</code>, <code>cross apply</code>/<code>outer apply</code> und andere.</p><p><strong> betrachten sie den folgenden datensatz: </strong></p><pre><code>create table dbo.lotr(lotrid int, charactername varchar(255), val varchar(255)); create table dbo.lotrattributes(lotrattributeid int, lotrid int, attrval varchar(255)); insert into dbo.lotr(lotrid,charactername,val) values(1,'frodo','ring') ,(2,'gandalf','staff'); insert into dbo.lotrattributes(lotrid,lotrattributeid,attrval) values(1,1,'ringattribute1') ,(1,2,'ringattribute2') ,(1,3,'ringattribute3') ,(2,4,'staffattribute1') ,(2,5,'staffattribute2'); </code></pre><p>man könnte versuchen, jeden datensatz zu finden, und er stimmt separat überein, indem man die tabelle <code>lotr</code> durchläuft.</p><p><strong> cursor: </strong></p><pre><code>declare @lotrid int declare c cursor for select lotrid from dbo.lotr; open c fetch next from c into @lotrid; while @@fetch\_status = 0 begin select lotrattributeid from dbo.lotrattributes where lotrid = @lotrid; fetch next from c into @lotrid; end close c deallocate c </code></pre><p><strong> das ergebnis sind zwei ergebnismengen </strong></p><pre><code>lotrattributeid 1 2 3 lotrattributeid 4 5 </code></pre><p><strong> wenn dieses <code>inner join</code> verwendet wird, erhalten wir das gleiche ergebnis wie eine ergebnismenge. </strong></p><pre><code>select lotrattributeid from dbo.lotr l inner join dbo.lotrattributes la on l.lotrid = la.lotrid; lotrattributeid 1 2 3 4 5 </code></pre><hr><h2>string-manipulation</h2><p>häufig wird <code>for xml path('')</code> verwendet, um zeichenfolgenmanipulationen innerhalb von cursorn zu ersetzen.</p><p><strong> datensatz </strong></p><pre><code>create table dbo.lotr(lotrid int, charactername varchar(255), val varchar(255)); create table dbo.lotrattributes(lotrattributeid int, lotrid int, attrval varchar(255)); insert into dbo.lotr(lotrid,charactername,val) values(1,'frodo','ring'); insert into dbo.lotrattributes(lotrid,lotrattributeid,attrval) values(1,1,'ringattribute1') ,(1,2,'ringattribute2') ,(1,3,'ringattribute3'); </code></pre><p><strong> doppelcursor mit string-manipulation </strong></p><pre><code>declare @lotrid int, @charactername varchar(255), @val varchar(255) declare @lotrattributeid int, @attrval varchar(255) declare c cursor for select lotrid,charactername, val from dbo.lotr open c fetch next from c into @lotrid,@charactername,@val while @@fetch\_status = 0 begin set @charactername +='|'+ @val declare d cursor for select lotrattributeid, attrval from dbo.lotrattributes where lotrid = @lotrid open d fetch next from d into @lotrattributeid,@attrval while @@fetch\_status = 0 begin set @charactername +='['+@attrval+ '],' fetch next from d into @lotrattributeid,@attrval end close d deallocate d fetch next from c into @lotrid,@charactername,@val end close c deallocate c select left(@charactername,len(@charactername)-1); </code></pre><p><strong> ergebnis </strong></p><pre><code>(no column name) frodo|ring[ringattribute1],[ringattribute2],[ringattribute3], </code></pre><p><strong> entfernen der cursor mit for xml path ('') </strong></p><pre><code>select l.charactername +'|'+ l.val + (select stuff((select ','+quotename(attrval) from dbo.lotrattributes la where la.lotrid = l.lotrid for xml path('')), 1, 1, '')) from dbo.lotr l; </code></pre><h2>* *</h2><p>die eigentliche problemumgehung besteht darin, herauszufinden, warum die daten auf diese weise dargestellt werden, und die anwendung zu ändern, um sie nicht in diesem format zu benötigen, und sie irgendwo zu speichern.</p><p>wenn ihre hände gebunden sind, wäre dies das nächstbeste.</p><hr><h2>fügen sie die top-10-werte in eine temporäre tabelle ein, basierend auf den ids in einer anderen tabelle</h2><p><strong> daten </strong></p><p>create table dbo.sometable (inserttableid int, val varchar (255)); create table dbo.top10table (top10tableid int, inserttableid int, val varchar (255));</p><pre><code>insert into dbo.sometable(inserttableid,val) values(1,'bla') ,(2,'blabla'); insert into dbo.top10table(top10tableid,inserttableid,val) values(1,1,'wuw') ,(2,1,'wuw') ,(3,1,'wuw'); </code></pre><p><strong> cursor </strong></p><pre><code>create table #top10values(top10tableid int, inserttableid int, val varchar(255)) declare @inserttableid int; declare c cursor for select inserttableid from dbo.sometable; open c fetch next from c into @inserttableid; while @@fetch\_status =0 begin insert into #top10values(top10tableid,inserttableid,val) select top(10) top10tableid,inserttableid,val from dbo.top10table where inserttableid = @inserttableid order by top10tableid fetch next from c into @inserttableid; end close c deallocate c select * from #top10values; drop table #top10values; </code></pre><p><strong> ergebnis </strong></p><pre><code>top10tableid inserttableid val 1 1 wuw 2 1 wuw 3 1 wuw </code></pre><p><strong> ersetzen des cursors durch <code>cross apply</code> und ein <code>cte</code> </strong></p><pre><code>create table #top10values(top10tableid int, inserttableid int, val varchar(255)); ;with cte as ( select inserttableid from dbo.sometable ) insert into #top10values(top10tableid,inserttableid,val) select t1t.top10tableid,t1t.inserttableid,t1t.val from cte cross apply (select top (10) top10tableid,inserttableid,val from dbo.top10table t1t where t1t.inserttableid = cte.inserttableid ) t1t ; select * from #top10values; drop table #top10values; </code></pre><hr><h2>andere beispiele</h2><ul> <li>ein beispiel zum ersetzen eines cursors zur auswahl eines dynamischen satzes von artikeln pro lieferant mithilfe von <code>cross apply</code> <a href="https://dba.stackexchange.com/questions/100761/replacing-a-cursor-with-a-single-query-possible">hier</a> .</li> <li>ein beispiel für die verwendung von fensterfunktionen zum ersetzen eines cursors <a href="https://dba.stackexchange.com/questions/127083/improve-a-query-using-cursor-to-set-based-approach">hier</a> .</li> </ul><hr><p><strong> manchmal gibt es keine andere wahl </strong></p><p>wenn sie nicht in sätzen arbeiten können und zeilenweise arbeiten müssen, können sie den cursor trotzdem optimieren.</p><p>eine der größten änderungen bei der beschleunigung des cursors ist das hinzufügen von <code>local fast\_forward</code>.</p><pre><code>declare c cursor local fast\_forward for select lotrid from dbo.lotr </code></pre><p>schauen sie sich <a href="https://sqlperformance.com/2012/09/t-sql-queries/cursor-options">diesen blogpost</a> von @aaronbertrand an, wo er die möglichen leistungsunterschiede erklärt, wenn cursoreinstellungen wie <code>local</code> &amp; <code>fast\_forward</code> verwenden oder nicht.</p> <p>möchten sie, dass es funktioniert, ohne einen zusätzlichen befehl einzugeben, z.</p><pre><code>$ rm file </code></pre><p>oder nur, wenn der benutzer so etwas eingibt</p><pre><code>$ confirm rm file </code></pre><p>oder nur, wenn der benutzer versucht, bestimmte befehle auszuführen, z.</p><pre><code>$ rm file </code></pre><p>aber nicht für</p><pre><code>$ echo "hello" </code></pre><p>bei option 1 kann dies mit dem preexec-hook in zsh oder der debug-trap in bash erfolgen.</p><p>fügen sie bei option 2 so etwas in <code>/etc/bash.bashrc</code> oder eine andere shell-startdatei ein.</p><pre><code>confirm() { echo -n "do you want to run $*? [n/y] " read -n 1 reply echo if test "$reply" = "y" -o "$reply" = "y"; then "$@" else echo "cancelled by user" fi } </code></pre><p>bei option 3 können sie das <code>confirm</code> -skript oben ändern, oder einige befehle haben eine option, die sie fragen können, bevor sie etwas tun, z. <code>rm -i</code>. sie könnten <code>alias rm='rm -i'</code> in <code>/etc/bash.bashrc</code> einfügen.</p> <p>um sonderzeichen in einem like-ausdruck zu maskieren, wird ihnen ein escape-zeichen vorangestellt. sie können auswählen, welches escapezeichen mit dem escape-schlüsselwort verwendet werden soll. ( <a href="http://msdn.microsoft.com/en-us/library/ms179859.aspx">msdn ref</a> )</p><p>dies maskiert beispielsweise das% -symbol mit\als escapezeichen:</p><pre><code>select * from table where myfield like '%15\% off%' escape '\' </code></pre><p>wenn sie nicht wissen, welche zeichen in ihrer zeichenfolge enthalten sein werden, und sie sie nicht als platzhalter behandeln möchten, können sie allen platzhalterzeichen ein escapezeichen voranstellen, z.</p><pre><code>set @mystring = replace( replace( replace( replace( @mystring , '\', '\\' ) , '%', '\%' ) , '\_', '\\_' ) , '[', '\[' ) </code></pre><p>(beachten sie, dass sie auch ihrem escape-zeichen entkommen müssen und sicherstellen müssen, dass dies das innere <code>replace</code> ist, damit sie nicht den anweisungen entgehen, die aus den anderen <code>replace</code> -anweisungen hinzugefügt wurden.) dann können sie so etwas verwenden:</p><pre><code>select * from table where myfield like '%' + @mystring + '%' escape '\' </code></pre><p>denken sie auch daran, mehr platz für ihre @ mystring-variable zu reservieren, da diese mit dem ersetzen der zeichenfolge länger wird.</p> <p>ich denke, dies wirft weitere fragen und potenzielle probleme auf:</p><ol> <li>ist es wirklich notwendig, zwei getrennte arten von feldern für diese arten von zahlen zu haben? die tatsache, dass sie probleme haben, sie richtig zu kennzeichnen, bedeutet, dass dies wahrscheinlich zu einer schlechten benutzererfahrung führt.</li> <li>was ist, wenn der benutzer der meinung ist, dass die antwort eine dezimalstelle enthält, aber nur eine ganze zahl eingeben darf? sollten sie auf- oder abrunden?</li> <li>gibt es eine möglichkeit, sie nur mit einem nummernfeld zu versehen und den rest programmgesteuert zu erledigen? vielleicht dezimalstellen runden oder entfernen?</li> </ol><p>wenn sie sie nicht zu einem feldtyp kombinieren können, können sie sie auf jedem etikett explizit angeben:</p><ul> <li>geben sie eine zahl ein (dezimalstellen erlaubt)</li> <li>geben sie eine zahl ein (keine dezimalstellen)</li> </ul> <h1><code>sudo su postgres</code></h1><p>nachdem ich diese <a href="https://stackoverflow.com/q/7765269/642706">geschlossene frage zum stapelüberlauf</a> und <a href="https://stackoverflow.com/q/23982282/642706">sein duplikat</a> gefunden habe, werde ich hier die gefundenen lösungen veröffentlichen <a href="https://stackoverflow.com/a/7765367/642706">dort</a> und <a href="https://stackoverflow.com/a/23982810/642706">dort</a> .</p><p>➥ sie müssen den befehl <code>sudo</code> <em> kombiniert</em> mit dem befehl <code>su</code> verwenden.</p><pre class="lang-bash prettyprint-override"><code>sudo su postgres </code></pre><p>wenn sie dazu aufgefordert werden, geben sie ihr <strong> macos-administratorbenutzerkennwort </strong> anstelle des kennworts <code>postgres</code> ein. zu diesem zeitpunkt ist ihr mac-administrator derjenige, der den befehl <code>sudo</code> ausführt, nicht der benutzer <code>postgres</code>.</p><p>ich verstehe zwar nicht, warum wir das <code>sudo</code> mit dem <code>su</code> kombinieren müssen, aber es funktioniert tatsächlich für mich in <a href="https://en.wikipedia.org/wiki/macos\_mojave">macos mojave</a> . ich habe diesen tipp bei meinen verschiedenen suchanstrengungen im zusammenhang mit bsd und linux nicht gefunden. vielleicht handelt es sich also nur um einen mac apple, möglicherweise um eine zusätzliche sicherheitsmaßnahme. oder unter betriebssystemen im unix-stil muss der befehl <code>su</code> vom benutzer <code>root</code> ausgeführt werden, und unter macos ist das konto <code>root</code> aus sicherheitsgründen standardmäßig deaktiviert - unser das mac-administrator-benutzerkonto ist weniger leistungsfähig als <code>root</code> und möglicherweise nicht standardmäßig zum ausführen von <code>su</code> autorisiert. keine ahnung, egal, die problemumgehung funktioniert.</p><h2>moderne alternative: <code>sudo -u</code></h2><p>nach <a href="https://stackoverflow.com/a/23988605/642706">zu craig ringer</a> und <a href="https://stackoverflow.com/a/23982810/642706">zu erwin brandstetter</a> ist die modernere form:</p><pre class="lang-bash prettyprint-override"><code>sudo -u postgres -i </code></pre><p>laut <a href="https://www.sudo.ws/man/1.8.3/sudo.man.html">diese seite</a> :</p><ul> <li><code>-u</code> bedeutet "einen angegebenen befehl als diesen angegebenen benutzer ausführen".</li> <li><code>postgres</code> gibt den benutzernamen an, unter dem der befehl ausgeführt werden soll.</li> <li><code>-i</code> simuliert eine anfängliche anmeldung, dh die shell wird mit den startskripten des benutzers initialisiert.</li> <li>da kein befehl bereitgestellt wird, wird eine interaktive shell ausgeführt.</li> </ul><p>weitere informationen zu älteren und neueren ansätzen finden sie in dieser frage auf der schwesterseite <a href="https://serverfault.com/q/601140/142214"><em> was ist der unterschied zwischen sudo su - postgres und sudo -u postgres ?</em></a> . die antwort von craig ringer lautet: (a) vergessen sie <code>sudo su</code> und (b) verwenden sie stattdessen <code>sudo -u</code>.</p><h3>führen sie apps als <code>postgres</code> benutzer aus</h3><p>so führen sie eine <a href="https://en.wikipedia.org/wiki/postgresql#psql"><code>psql</code></a> sitzung als <code>postgres</code> benutzer aus:</p><pre class="lang-bash prettyprint-override"><code>sudo -u postgres psql </code></pre><p>so führen sie die <a href="https://en.wikipedia.org/wiki/gnu\_nano"><code>nano</code></a> <a href="https://en.wikipedia.org/wiki/text\_editor">texteditor</a> app als <code>postgres</code> benutzer aus:</p><pre class="lang-bash prettyprint-override"><code>sudo -u postgres nano </code></pre> <p>fügen sie ihrem <code>~/.bashrc</code> die folgende zeile hinzu:</p><pre><code>alias sudo='sudo ' </code></pre><p>aus dem <a href="http://www.gnu.org/software/bash/manual/bashref.html#aliases">bash manual</a> :</p><blockquote> <p>aliase ermöglichen das ersetzen eines worts durch eine zeichenfolge, wenn es als erstes wort eines einfachen befehls verwendet wird. die shell verwaltet eine liste von aliasen, die mit den integrierten befehlen alias und unalias festgelegt und deaktiviert werden können.</p> <p><strong> das erste wort jedes einfachen befehls wird, wenn es nicht in anführungszeichen gesetzt ist, überprüft, um festzustellen, ob es einen alias ​​</strong> enthält. in diesem fall wird dieses wort durch den text des alias ​​ersetzt. die zeichen "/", "$", "` "," = "und alle oben aufgeführten shell-metazeichen oder anführungszeichen erscheinen möglicherweise nicht in einem aliasnamen. der ersetzungstext kann eine gültige shell-eingabe enthalten, einschließlich shell-metazeichen. das erste wort des ersetzungstextes wird auf aliase geprüft, ein wort, das mit einem zu erweiternden alias ​​identisch ist, wird jedoch nicht ein zweites mal erweitert. dies bedeutet, dass beispielsweise ein alias ​​"ls" für "ls -f" verwendet werden kann und bash nicht versucht, den ersetzungstext rekursiv zu erweitern. <strong> wenn das letzte zeichen des alias-werts ein leerzeichen oder ein tabulatorzeichen ist, wird das nächste auf den alias ​​folgende befehlswort ebenfalls auf alias-erweiterung überprüft </strong>.</p> </blockquote><p><sup>(hervorhebung von mir).</sup><br> bash überprüft nur das erste wort eines befehls auf einen alias, alle wörter danach werden nicht überprüft. das heißt, in einem befehl wie <code>sudo ll</code> wird nur das erste wort (<code>sudo</code>) von der bash auf einen alias ​​überprüft, <code>ll</code> wird ignoriert. wir können bash anweisen, das nächste wort nach dem alias ​​(d. h. <code>sudo</code>) zu überprüfen, indem sie am ende des alias ​​ein leerzeichen einfügen.</p> <p>verwenden sie <code>addfield()</code>. hier ist ein beispiel:</p><pre><code>$query = db\_select('super\_long\_table', 'slt'); $query-&gt;addfield('slt', 'mys\_super\_long\_field', 'mslf'); </code></pre><p>an <code>addfield()</code> übergebene argumente sind:</p><ul> <li>tabellenalias</li> <li>feld - ihr langer feldname wird hier sein</li> <li>alias ​​- ihr kurzfeld-alias ​​wird hier sein</li> </ul><p>lesen sie mehr darüber <a href="https://api.drupal.org/api/drupal/includes!database!select.inc/function/selectqueryinterface%3a%3aaddfield/7">hier</a> .</p>