wtorek, 15 lutego 2011

Azure UNICODE Friendly

Jeszcze jedna ciekawostka ze świata Azure jest taka, że jest on bardzo UNICODE. Jeżeli w tabelce mamy pole typu VARCHAR, a w nim np. słówko 'PAWEŁ' to szukając prostym zapytaniem :
SELECT *
FROM TABELKA
WHERE NAZWA = 'PAWEŁ';
... otrzymamy zero wyników. Azure sprytnie zamienia sobie "Ł" na "L" i szuka 'PAWEL' i oczywiście nie znajduje. Rozwiązania na znalezienie interesujących nas rekordów są dwa : zmiana pola z VARCHAR na NVARCHAR lub napisanie zapytania w taki sposób :
SELECT *
FROM TABELKA
WHERE NAZWA = N'PAWEŁ';

środa, 19 stycznia 2011

Azure

Ostatnio miałem okazję przyglądać się pracom przenoszenia aplikacji do chmury. Ciekawe był sposób sprawdzania poprawności przenoszonego kodu SQL. Jednej z procedur serwerowych nie można było przenieść do bazy w chmurze. Pojawiał się błąd (dokładnie nie pamiętam angielskiej wersji), że tworzenie globalnej tabeli tymczasowej nie jest dozwolone. Zajrzeliśmy do wnętrza procedury, ale nie znaleźliśmy kodu odpowiedzialnego za tworzenie globalnej tabeli tymczasowej. Była tam deklaracja lokalnej tabeli. Myśleliśmy, że to w tym problem. Zmieniliśmy kod tworzenia tabeli tymczasowej na tworzenie zmiennej tabelarycznej. Niestety nie pomogło.

Po kolejnym okrążeniu kodu procedury okazało się, że w jednym z zapytań (zwykłe polecenie SELECT) w klauzuli WHERE było coś takiego :
WHERE NAZWA LIKE 'XYZ ##%##%'
Zakomentowaliśmy tą linijkę kodu i proces zakładania procedury przeszedł bez błędów.

Z tego wynika, że tak naprawdę nie było szukane tworzenie globalnej tabeli tymczasowej, a dwóch #. Okazuje się, że dwa # są zawsze oznaczenie globalnej tabeli tymczasowej ;).

Co Wy na to, bo dla mnie taka walidacja kodu to trochę nie fajnie?

czwartek, 30 grudnia 2010

UPDATE CTE

Ostatnio, jeden z moich znajomych miał do napisania skrypt, który do istniejącej tabeli doda kolumnę ID i uzupełni ją danymi (ponumeruje wiersze). Pierwsza myśl jaka mi przyszła do głowy to wykorzystanie funkcji ROW_NUMBER() do ponumerowania wierszy. Przykładowa tabelka, już z dodaną kolumną ID poniżej.


USE TEMPDB;
GO

CREATE TABLE T
(
      ID INT NULL,
      VAL VARCHAR(10)
);

INSERT INTO T (ID, VAL)
VALUES (NULL, 'A')
      , (NULL, 'B')
      , (NULL, 'C');

SELECT *
FROM T; 























Mamy więc już tabelkę z kolumną ID, ale jeszcze wartość w kolumnie to NULL. Jak ponumerować wiersze? O tym poniżej.

W pierwszej kolejności przygotowujemy sobie CTE, w którym dodajemy do tabelki nową kolumnę (u mnie to jest TEMPID), która powstaje z wykorzystania funkcji ROW_NUMBER(). Mając już tak przygotowane CTE robimy prosty UPDATE, który przepisze nam wartość z TEMPID do naszej kolumny ID do tabelki T. Dziwne jest to, że UPDATE robimy na CTE, a nie bezpośrednio na tabeli. Mimo to w magiczny sposób kolumna ID w naszej tabli zostaje zmieniona.

WITH TCTE
AS
(
      SELECT ROW_NUMBER() OVER (ORDER BY VAL ASC) AS TEMPID
            , ID
            , VAL
      FROM T
)
UPDATE TCTE
SET ID = TEMPID;

SELECT *
FROM T; 


















Poniżej jeszcze skrypt w całości.

USE TEMPDB;
GO

CREATE TABLE T
(
      ID INT NULL,
      VAL VARCHAR(10)
);

INSERT INTO T (ID, VAL)
VALUES (NULL, 'A')
      , (NULL, 'B')
      , (NULL, 'C');

SELECT *
FROM T;

WITH TCTE
AS
(
      SELECT ROW_NUMBER() OVER (ORDER BY VAL ASC) AS TEMPID
            , ID
            , VAL
      FROM T
)
UPDATE TCTE
SET ID = TEMPID;

SELECT *
FROM T;

DROP TABLE T;