понедельник, 15 июня 2009 г.

T-SQL. Вставка unicode-данных.

Проблема при попытке вставить unicode-данные в поле типа ntext с помощью SQL-оператора INSERT:

INSERT INTO MyTable (Field1) VALUES ('Операциялық жүйе');

Вставленные данные выглядят следующим образом: "Операциялы? ж?йе" (национальные символы заменены вопросами).

Причина в том, что вставляемый текст автоматически конвертируется в 8-ми битную кодировку (1251 в данном случае).

Решение: перед unicode-текстом делаем префикс "N":

INSERT INTO MyTable (Field1) VALUES (N'Операциялық жүйе');

Символ "N" перед вставляемым текстом указывает MS SQL Server'у на то, что данный текст следует обрабатывать в кодировке unicode.

воскресенье, 14 июня 2009 г.

T-SQL. Выбор N случайных записей из таблицы БД.

Задача: СУБД MS SQL Server 2005, требуется выбрать случайные записи из таблицы MyTable в количестве N штук.
Решение: использовать функцию NEWID(), которая генерирует случайный GUID:

SELECT TOP(@N) * FROM MyTable ORDER BY NEWID()

где @N - параметр, количество записей.
Приведённый выше запрос с помощью NEWID() генерирует случайный GUID (строку вроде "686c1b0f-4bae-4c58-8a19-01904a67c3d8") для каждой записи таблицы, затем сортирует результат по этим GUID и выбирает первые N записей.

пятница, 5 июня 2009 г.

Псевдонимы MS SQL Server

Когда несколько человек работают над одним проектом, используя систему контроля версий (например, SVN), то часто бывает следующая ситуация. Строка соединения с БД прописана в конфигурационном файле, причем имя сервера и экземпляра установлено жестко, например: almaz\base. Здесь almaz - имя сервера, base - экземпляр MS SQL Server'а. Но у меня компьютер называется PC, а экземпляр БД - SQLEXPRESS, значит мне в строку соединения нужно прописать PC\SQLEXPRESS. Поддерживать свои конфигурационные файлы в актуальном состоянии, а именно - после каждого update менять строку соединения, неудобно.

Выход - использовать псевдонимы MS SQL Server'а.
Итак, задача - настроить на локальном компьютере псевдоним, отображающий сервер "almaz\base" в "PC\SQLEXPRESS".

Решение. Открываем SQL Server Configuration Manager, переходим в раздел "Конфигурация собственного клиента" -> "Псевдонимы"



Затем вызываем контекстное меню -> "Создать псевдоним..." и заполняем поля в появившемся окне



Имя псевдонима - желаемое имя, в моем случае - это "almaz\base".
Порт № - по умолчанию 1433.
Сервер - реальное имя сервера и экземпляра, в моем случае - "PC\SQLEXPRESS".

Готово. Открываем Management Studio и пробуем соединиться с сервером "almaz\base". Соединение проходит на ура.

среда, 27 мая 2009 г.

Подсветка синтаксиса в блоге на Blogspot.com

Здесь мы будем использовать SyntaxHighlighter http://code.google.com/p/syntaxhighlighter/.

Для того, чтобы в своём блоге сделать подсветку синтаксиса HTML, CSS, C++, Delphi, C#, Java, SQL и прочего кода, делаем следующее:

Открываем свой блог Заходим в Настройки -> Макет -> Изменить Html и вставляем между закрывающими тэгами </body> и </html> следующий код:


</body>

<link href='http://8296241635750553491-a-1802744773732722657-s-sites.googlegroups.com/site/syntaxhighlightersite/Home/SyntaxHighlighter.css' rel='stylesheet' type='text/css'/>

<-- подключаем модули для языков, которые собираемся подсвечивать -->
<script language='javascript' src='http://syntaxhighlighter.googlecode.com/svn/trunk/Scripts/shCore.js'/>
<script language='javascript' src='http://syntaxhighlighter.googlecode.com/svn/trunk/Scripts/shBrushCSharp.js'/>
<script language='javascript' src='http://syntaxhighlighter.googlecode.com/svn/trunk/Scripts/shBrushXml.js'/>
<script language='javascript' src='http://syntaxhighlighter.googlecode.com/svn/trunk/Scripts/shBrushCss.js'/>
<script language='javascript' src='http://syntaxhighlighter.googlecode.com/svn/trunk/Scripts/shBrushCpp.js'/>
<script language='javascript' src='http://syntaxhighlighter.googlecode.com/svn/trunk/Scripts/shBrushDelphi.js'/>
<script language='javascript' src='http://syntaxhighlighter.googlecode.com/svn/trunk/Scripts/shBrushJScript.js'/>
<script language='javascript' src='http://syntaxhighlighter.googlecode.com/svn/trunk/Scripts/shBrushJava.js'/>
<script language='javascript' src='http://syntaxhighlighter.googlecode.com/svn/trunk/Scripts/shBrushPhp.js'/>
<script language='javascript' src='http://syntaxhighlighter.googlecode.com/svn/trunk/Scripts/shBrushSql.js'/>

<script language='javascript'>
dp.SyntaxHighlighter.ClipboardSwf = 'http://syntaxhighlighter.googlecode.com/svn/trunk/Scripts/clipboard.swf';
dp.SyntaxHighlighter.BloggerMode();
dp.SyntaxHighlighter.HighlightAll('code');
</script>

</html>


Сохраняем макет. Переходим в тело сообщения и оформляем наш код (который нужно подсветить) следующим образом:

<pre name="code" class="!Название языка программирования!">
</pre>

Где !Название языка программирования! - один из следующих вариантов:

Язык Названия
C++ cpp, c, c++
C# c#, c-sharp, csharp
CSS css
Delphi delphi, pascal
Java java
Java Script js, jscript, javascript
PHP php
Python py, python
Ruby rb, ruby, rails, ror
Sql sql
VB vb, vb.net
XML/HTML xml, html, xhtml, xslt


Поддержка каждого языка реализована в отдельном js-файле. Его необходимо подключить в шаблоне (как показано выше), если вы планируете подсвечивать синтаксис этого языка.
Полный список языковых модулей здесь:
http://code.google.com/p/syntaxhighlighter/source/browse/trunk/#trunk/Scripts.

Пример оформления JavaScript-кода:

<pre name="code" class="js">
function AllEmptyValidator(source, clientside_arguments)
{
var tbl = document.getElementById("tbl_" + source.id);
var elements = tbl.getElementsByTagName("input");
for(var i = 0; i > elements.length; i++)
{
if(elements[i].value.length > 0)
{
clientside_arguments.IsValid = true;
return;
}
}

//default - all are empty, it is not valid
clientside_arguments.IsValid = false;
}
</pre>

Результат:


function AllEmptyValidator(source, clientside_arguments)
{
var tbl = document.getElementById("tbl_" + source.id);
var elements = tbl.getElementsByTagName("input");
for(var i = 0; i > elements.length; i++)
{
if(elements[i].value.length > 0)
{
clientside_arguments.IsValid = true;
return;
}
}

//default - all are empty, it is not valid
clientside_arguments.IsValid = false;
}

суббота, 18 апреля 2009 г.

Oracle PL/SQL: условные вставки

Условные вставки (conditional inserts) в PL/SQL - это расширенный SQL-оператор INSERT. Он позволяет вставлять записи в базу данных при выполнении какого-то логического условия. Например, вставить элемент в таблицу-справочник, если элемента с таким именем в этой таблице ещё нет:

INSERT

WHEN

NOT EXISTS

(

SELECT NULL FROM items t

WHERE t.name=:name

)

THEN

INTO items (id, name)

VALUES (ID, NAME)

SELECT :id AS ID, :name AS NAME FROM dual;



В упрощённом виде синтаксис этого оператора таков:

INSERT

WHEN ([Condition]) THEN

INTO [TableName] ([ColumnName])

VALUES ([VALUES])

ELSE

INTO [TableName] ([ColumnName])

VALUES ([VALUES])

SELECT [ColumnName] FROM [TableName];

Oracle PL/SQL: постраничный доступ к данным

При написании Web-приложений часто требуется организовать постраничный просмотр данных. Классический пример - результаты поискового запроса на любом поисковике (Google, Yandex, ...).

Самый примитивный способ - выбрать все необходимые строки из таблицы, (например: SELECT * FROM items), а затем на стороне клиента разбить результат на страницы и вывести нужную страницу. Этот подход я рассматривать не буду, т.к. для больших таблиц он совершенно неприемлем.

Большинство СУБД имеют встроенные средства, для ограничения результатов запроса сверху и снизу. Кроме того стандарт ISO SQL:2003 предусматривает функции ROW_NUMBER() и RANK() для этих целей. Подробнее в этой статье на Wiki.

Для Oracle мне больше всего нравится способ, который предлагает Том Кайт. Он основан на использовании псевдо-колонки ROWNUM, а также того факта, что в Oracle есть специальный механизм повышающий производительность для запросов первых N строк.

PL/SQL код для реализации постраничного доступа к результатам запроса (pagination of query result):

TYPE CItems IS REF CURSOR; -- возвращаемый курсор

CONST_ITEMS_PER_PAGE CONSTANT NUMBER := 25; -- количество элементов на странице

-- возвращает количество страниц в базе данных
FUNCTION get_items_pages_count()
RETURN NUMBER IS

cnt NUMBER; -- количество элементов

BEGIN
-- определяем количество элементов
SELECT COUNT(*) INTO cnt
FROM items t;

-- делим количество_элементов на количество_элементов_на_странице
-- и округляем полученное к большему целому
RETURN CEIL(cnt / CONST_ITEMS_PER_PAGE);
END;

-- возвращает все элементы на данной странице
PROCEDURE get_items_page(
cur OUT CItems, -- возвращаемый курсор
p_page IN NUMBER, -- номер страницы (корректность не проверяется)
) IS

rnum_first NUMBER; -- номер первой записи на странице
rnum_last NUMBER; -- номер последней записи на странице

BEGIN
-- получаем диапазон номеров строк, которые будем возвращать
rnum_first := (((p_page-1)*CONST_ITEMS_PER_PAGE)+1);
rnum_last := (p_page*CONST_ITEMS_PER_PAGE);

-- закрываем курсор, если он уже открыт
IF cur%ISOPEN THEN
CLOSE cur;
END IF;

-- открываем курсор
OPEN cur FOR
-- этот запрос "отрезает" от подзапроса первые rnum_first строк снизу
SELECT t2.*
FROM
(
-- этот запрос вытаскивает первые rnum_last строк из исходного запроса
SELECT t1.*, ROWNUM AS rnum
FROM
(
-- это наш исходный запрос, который будем разбивать на страницы
SELECT t.*
FROM items t
) t1
WHERE ROWNUM <= rnum_last -- верхняя граница
) t2
WHERE t2.rnum >= rnum_first; -- нижняя граница
END;

среда, 1 апреля 2009 г.

Oracle import

imp 'SYS/pass AS SYSDBA' FROMUSER=MIKE TOUSER=JOHN file=mike_db.dmp log=log.txt

Обращаем внимание на апострофы здесь: 'SYS/pass AS SYSDBA'. В Windows без этих апострофов импорт будет ругаться на AS SYSDBA.
MIKE - пользователь, который экспортировал, JOHN - пользователь, который импортирует. У JOHN'а должны быть соответствующие привелегии на TABLESPACE, создание таблиц, и т.д.

Полное описание imp.exe: http://download.oracle.com/docs/cd/A87860_01/doc/server.817/a76955/ch02.htm#16959