Разделы
Публикации
Популярные
Новые
|
Главная » Оптимизация производительности transact 1 ... 45 46 47 48 49 50 51 ... 55 функции, возвращающие наборы данных 489 Мо.кии иеиользивать оператор FORMSOF() для нахождения различи!! времен 1ла1-о.ча, так же как и еди1!стве1И!Ого и !lloжecтвeниolч) числа существи ге.чьного. В этом случае приведет!!,!!! KOi! иа11дет пять Baiiiiceii, содержащих формтч слова <.с(лир1е(Ч' . 1И<л1очая coiiipleted-> и coiiipleLingv. Предикат FREETEXT() FREETEXTO полезен для ионПча BaiiTiceii, солержа11и1х слова, кочортяо имеюч' то же основное зиаче1И!е, ччо и с.чова !!3 строки поиска. В о-1Л1!Чне от CONTAINS(), FREETEXTO позволяет yiai3aTi, iia(5op условть koioi)i4.m зате.м Г1р1!сваица1отся виутре!!11!1е веса, и ohi! со1!оставляются со зпачения.х!!! и столонах. Вот пример, котор!)!!! 1!ахолит сот[)уд1!Икои, зак()нчпв1иих кчпледж. прежде всего - с дипло-.мом бака.чавра; SELLC LastNaii.e, MTstName Notes FROM Lir.p:oyees WHERF FREETE.XT;Notes.BA BES BS BSC degree) (результаччч сокра1де!1ы) Janet has a ES degree in chenistry frcm Boston Enucation includes a BA m osyciiology Margaret holds a БА in English literature from Anne has a BA degree in Englisn fnom St. Andr-ew received his BIS commercial in 1974 and Robert King [completed] his degree 1n English at Steven Buchanan graduated with a BSC degree in Laura received a BA in psychology from the Здесь в 1)езульта!-ы попадает любая запись, содержа1!!ая услов!1я поиска и.чи похожие сло1за. Так же как и с CONTAII\IS(), .можно ис11ол1,зовать * для обозначения всех столбцов, входящих в 1!Олиотекс1ЮВ1лй !!ндекс таблицы. Функции, возвращающие наборы данных В Transact-SQL 0!1ределеп С!1е11иалыил1 1 1счасс фу!!кц!п'1, возвращающих наборы данных (rowset functions), которые мож!!о испол1>зовать в.место табл!!!! !s выра-же1!1!и FROM 3a!ipocoB. Функщ!!!, возвраща1ощ!1е наборы дан!!Ь!Х, возвращают 1!аб01)Ь! Да1!НЬ!х подобно Пр01!ЗВ0Д!!Ь!М Таб.Ч1!ЦаМ I! !OГyт б!)!ТЬ объед1!пе1!ы с !!а- стояши.мн таб^шца.ми, и])осумл!1!рова1!Ь!, сгруппированы i! так далее. К пол1!Отекстовому поиску относятся две так!!е фу!!К!Ц!и: CONTAINSTABLE() и FREETEXTTABLEO. Это верси!! обсуждеи!!ЫХ ранее в это! ! главе предикатов, воз-вращаю1Ц!1е 1!аборь! данных. В.место В1)1ражения WHERE о!1и обычно располагаются в выражен!!!! FROM оператора SELECT. Онт! возвращают резулыг!1рую1Ц!!11 набор, состоящт!!) !!3 ключевых 3!!ачен!!Й индекса и ранга запис!!. Функция CONTAINSTABLEO Вдобавок к то.му, что эта (>ункция возвра1!!ает набор да!1НЬ!Х, oi!a работает так же, как т! пред!!кат CONTAINSO, что следует т!з ее названия. Она поддерж!!!!ает
490 Глава 18, Полногекстовый поиск точно такие же условия поиска, что и CONTAINS(), и принимает- па один пара.метр больше, че.м предикат, - это название таблицы. Вог [тример, используюннн! CONTAINSTABLEO д.тя получения списка ключевых зиачениГ! и рапжцрова]Н!я: SELECT - FROM CC.NiAlNSTABLECEmployees,*.English OR French OR Italian OR German OR Fiemsn; ORDER B RANK OESC ,<EY RAIv.K 2 64 4 48 7 48 9 48 6 32 5 32 CONTAINSTABLEO возвращает два столбца; к..ночевое значение записи из таблицы и ранг каждой записи. В это.м при.мере используется столбец RANK для логического ностроетнгя записей, так что сначала выводятся записи с более высоким рангом. Ключевые значения можно при.менить при объединении с исходной таблицей для получения более ос.мыслегнюй тии})ор.\1ации, как вскоре можно будет убедиться. Ранги из столбца RANK .можно приспособить для ваших целей нрп по.чгощи функции ISABOUT(): SELECT * FROM CONTAINSTABLE(Employees.*,ISABOorcEnglish weight!0.8), Frencn weight(0,l), Italian weight(C.2), German weight(0,4), Flemish weight(O.O))) ORDER BY RANK DESC KEY RANK 9 85 2 54 4 47 7 47 8 7 6 3 В ЭТО.М примере веса назначаются каждо.му языку в столбце Notes таблицы Employees. Веса и.меют значение от нуля для фламандского языка до 0,8 для аш-лийского. Допустимы значещгя веса от 0,0 до 1,0, Как и в предыдущем прп.мере, мы применяем столбец RANK для ностроешгя зашгсей так, что снача;к\ идут записи с наибольши.ми значен1гя.\ш этого столбца. Функция ISABOUT0 также доступна и в предикате CONTAINSO, но там от не имеет никакого эффекта, поскольку влияет на столбец RANK, который не используется предикато.м. Для получения действтгтельно выразительньгх результатов необходимо объединить результаты CONTAINSTABLEO с исходной таблицей. Ключевые значения и ранги са.ми по себе не особенно полезны, если не связаны с исходными данными. Вот пример: SELECT R.RANK. E.LastNam.e, Е.FirstName. Е,Notes FROM Employees AS E JOIN функции, возвращающие наборы даниш 491 сил AiNb ! ДБ:, t; Lip : Oyoei * IgABU ng i:; .-.c- griLiL.fc . riei;,- . ;vc;gi,:/C, Кг12:; weigr.tcC.2K Cermv. v fgit(0.-;. Mwsn vieignKO.C.!)) AS P. OH (i.SnployeelGR.fKHy]; :!;:;ГР pv R.RAHK DFSC (результаты coKpauieiibi) RA:i,. l.attNane FirstName Noies 85 OcGSwc-T Ariro . s bc-nr -r French and Се-;топ 64 pGlor Andrew -..iuent If Frer-cn ar-o Hal ian ana reeds German a- Peacock Margaret Mui-garet nuljs a EA n cnglish literature i? Kins Rocert ...before cor.Dieting ps degree in fngish Calohari Lajra ...neacs arc writes French 3 5..уаг!а Hicnael ...car -eac and wnte Frencn, Pcciguese. and 3 Buchanan Steven ...is fluent in French Простое виузренисе объединение но столбцу EmployeeiD габлицы Employees и сто.тбцу KEY нз результатов функции CONTAINSTABLEO - вес, что требуется для соедшюиия дву.ч таблии- Столбец KEY содержит значения из столбца EmployeeiD в запнся.х, возвращае.мых CONTAINSTABLE(), поэтому это работает. Как и в иредыдуци1Х при.мерах. :-)тот запрос выстраивает свои результагы при по.\н)ЩП столбца RANK. Обратите вни.маипе иа иснользовапне квадратных скобок ( [] >) вокруг ссылки на столбец KEY. SQL Server ио непонятной прнчшю использует KEY как и.мя столбца в результагах CONTAINSTABLEO, хотя это и заре-.зервированное слово. Это вынуждает пр]гменять скобки (или двойные кавычки, если включен режи.м QUOTEDJDENTIFIER) во время ссылки на столбец KEY. Для того чтобы увидеть эффект взвешивания рангов, давайте исправн.м запрос так, чтобы при.меияюсь ранжирование Microsoft Search по умо.тчанию: SELECT R.R.ANK. е.LastName. E.FirstNane. Е,Notes FRCM Employees AS E JOIN CONTAINSTAELEiEmpioyees.*.English CR Frenc.-i OR Italian OR German OR Fle.mish) AS R ON CE.EmployeoIdR.LKEY]) ORDER BY R.RA.NK DESC (17ез\льтаты сокра!ЦС1ы) RANK LastName FinstNaine Notes
Как пид]гм, явно указанные весовые коэ(1)фицненты приводят к огром1Ш1м различия.м. Они полностью измеггяют порядок следования записей. Функция FREETEXTTABLEO Как и родственный предикат, функция FREETEXTTABLEO ишет записи, содержащие слова с те.м же са.мы\г основным значен1ге.м, что и указанные в критерии поиска. Фор.мат её гюискового крптерщ! свободный и не ггмеет специа-льного синтаксиса. ПоисконыЙ! механ]гз.\1 извлекает каждое слово из строки поиска, назна- чает слову вес и ищет записи соответственно. Вот ранее приведенньгй пример, который ищет сотрудников с дипломом бакалавра, переписанный для использования FREETEXTTABLE(): SELECT R.RANK. Е.LastName. Е,FirstName. Е,Notes FROM Employees AS E JOIN FREETEXnABLE(Employees,*,BA BTS BS BCS degree) AS R ON (E,EmployeeId=R,[KEY]) ORDER BY R.RANK DESC
Co столь широким критерием поиска запрос возвращает все записи, кроме одной, из таблицы Employees. Каждая из записей результата содержит одну из форм одного из слов критерия запроса. Заключение Функциональность полнотекстового поиска SQL Server - мощный инструмент, предоставляющий большую часть функций полноценных файловых поисковых машин. Включег[ие столбцов в текстовый поиск нетривиально, для этого следует применять Enterprise Manager или хранимую процедуру $р епаЫе fulltext (включенную в эту главу). После того как столбец включен в полнотекстовый поиск, предикаты COi\ITAIi\IS() и FREETEXT(), равно как и функции CONTAINSTABLEO и fREETEXTTABLE(), становятся доступны для использований. Они предлагают мощную альтернативу распространенным реализациям поиска, таким как LIKE и PATINDEX(). OLE-автоматизация lk:iL,y.\ia>iviibiM <л\шс иодобеп безбумажному туа/юту. Джо Селко SQL Server 11[)едостав.1мег набор хранимых процедур, назначение которых - работа с объекта.\П1 азгоматизацип, известно!! ранее Kaic ОЕЕ-авто.ччатпзация. Автомат!!за!!!1Я предоста13ляет 1!езависнмь!е от яз1тка способы управлен!1я i! пс-пол1>зовапия объектов, достуинь!х пз лрушх и])огра.м.м. Нанри.\!ер, .\!ожно нс-!10л|1301!;ггь автоматизацию, д.тя того чтобы проверят!! ор(}югра(})ию !!рп по.мощи Woixl или 1!ычислять локумс!!! при помощи Excel. Множество про1 ра.м.м и !hict-])у.ментов нредостав.чяют часчч, ciioeii (})}Ч1киио11а.чы1ости щюшне.му .миру че])ез o6beiai>i авто.мати.зации. Если h.mccioi досчуп к коичрочлер} авгоматиза!И1П, можно задействовать эти объект1>1 для у|1равле!1ия нриложеп!1е.м-хосто.м. К счастью, досгу|Т к тако.му коптр(хчле])у и.меется - средство ODSOLE !i3 cocraisa SQL Sei-vei-, представленное в виде набора системных !11)оцелур. которые .мож1!0 вь!31,1вать пз Transact-SQL. Относящиеся к авто.мачч1:!;!!цт хра!И1.мые п])оцелуры Transact-SQL названы в соответств!!!! с правпло.м sp OAFunction, 1де Function обозначаеч де1 ств!1е, 1!ы-по;н!яе.моо 11ро!!едуро| (н;и1])п.мер, sp OACreate сюздаег ;-)кзем1!ляр oobeicra авго-.мат|!зац!!1, sp OAMethod вызывает метод, sp OAGetProperty !i sp OASetProperty получают и уста1!а1!л1изают зпаче!!!1я свойств). Эта функция лоба!!ляет моши языку Transacl-SQL. Все, что можно сделать че1)ез нпгер(})ейс!>1 автомагизац|!и, ,мож1!0 вы1!0л!1Нть п]ти ПОМОЩИ Transaci-SQL. Для того чтобы проде.\!оистрпровать, как ,это работает, я покажу isa.m храии.мую процедуру, нспользу!0!цую авччтмаччгзацию для воспо.чпеиия иедоста!Още11 ())упкцноиалы!(Тсти в Tiansact-SQL. Возможно, !!ь1 помните, что в Ti-ansact-SQL есть кома1!да BULK INSERT, назначение KoiDpoii - загрузка фа11ча через иитер()епс массового копирован!1я. К сожалению, не су!цествует обрат1!ого !1нтерфе11са для экспорта данных. Можно предположить, что существует команда BULK EXPORT для экспорта даи!!ых в фа! 1л, но это не чак. Конечно, сушествует .\!асса cnoco6oii обойти это без пр1!мене1Н!я Transacl-SQL. Напр!1.мер, мож1!о 1!Спол1>зовать ути-л1!ту KON!anfl!!oii строки bcp.exe для экспорча данных. {Можно постро!!ть контроллер авто,мат!!,зац1И! !!ри помощи традиционных средств разработк!!, таких !<ак Visual Basic или Delphi. Мож!0 даже заде11СТ1Ювать для экспорта Entei-pi-ise Manager. Но ни один из этих альтернативных вариантов не будет столь забавен, как экспорт данных из Transact-SQL по отношению к BULK INSERT. В приведенных ниже примерах показано, как использовать хранимые процедуры автоматизации для автоматизации объектов самого сервера - Distributed Management Objects (SQL-DMO). Эти объекты предоставляют большую часть функциональности Enterprise Manager и являются удобным способом управления сервером при помощи про-гра.ммного кода. Обратите внимание, что вы не ограничены использованием объектов самого SQL Server. Можно работать с объектами, предоставляемыми любым приложением - Access, Visio, Visual С++ и т. п. sp exporttable Поскольку SQL Server предоставляет мощный интерфейс автоматизации к функции массового копирования в SQLDMO, мы можем написать Transact-SQL-код, выполняющий массовый экспорт при помощи Transact-SQL и названных ранее объектов автоматизации. Вот сценарий, создающий хратшмую процедуру: USE master GO IF (OBJECT IDCsp exporttable) IS NOT NULL) DROP PROC sp exporttable CREATE PROC sp exporttable @table varchar(12B). -- Таблица для экспорта @outputpath varchar(12B)=NULL. -- Выходной каталог IJoutputname varchar(12B)=NULL. -- Выходной файл (по уколчанию iatable+.ВСР') IJserver varchar(12B)=(local). -- Имя сервера IJusername varchar(12B)=sa. -- Имя учетной записи (по умолчанию sa) IJpassword varchar(i2B)=NULL -- Пароль учетной записи Объект: sp exporttable * Описание: Exports а table in а manner similar to BULK INSERT Использование: sp exporttable IJtable varchar(12B). -- Таблица для экспорта IJoutputpath varchar(12B)=NULL. -- Выходной каталог l?outputname varchar(12B)=NULL. -- Выходной файл (по умолчанию (atable+.ВСР') IJserver varchar(12B)=(local). -- Имя сервера IPusername varchar(12B)=sa, -- Имя учетной записи (по умолчанию sa) IPpassword varchar(12B)=NULL -- Пароль учетной записи Возвращает: количество экспортированных строк Автор: Ken Henderson. Email: khen@khen.com Пример: EXEC sp exponttable authors Создана: 1999-06-14. Изменена: 1999-07-14. IF (iatable=/?) OR (l?outputpath IS NULL) GOTO Help DECLARE IJobject int, -- Переменная для создания COM объектов @hr int. -- Хранит HRESULT l?bcobject int. -- Переменная для хранения указателя на объект BulkCopy @rAB DELIMlTED int, -- константа разделения табуляцией! @logname vanchan(128), -- Имя файла протокола Pemname varchar(128), -- Имя файла ошибок (adbname vanchar(12B), -- Имя базы (arowsexponted int -- количество зкспортированных строк SET (аТАВ 0ЕЕ1М1ТЕ0=2 -- константа SQL-DMO для экспорта с разделением SET @dbname=ISiNULL(PARSENAME((atable,3),DB NAME()) -- Извлечь имя базы: по умолчанию -текущая база SET (atable-PARSENAME(@tao1e,l) -- Убрать лишнее из имени таблицы IE (gtable IS NULL) BEGIN RAISERRORC Invalid table name 16,1) GOTO Help END IF (RIGHT((aojtputpath,l)<>\) SET (aoutputpath=@outputpatti+\ -- При необходимости добавить обратные: слэш SET (aiogname=@outputpath+@table+,LOG -- Составить полное имя файла протокола SET l?enrname=@outputpath+(atable+,ERR -- Составить полное имя фа(4ла ошибок IF ((aoutputname IS NULL)-- Составить полное имя выходного файла SET @outputname-(aoutputpatti+@table+ ,ВСР' ELSE IF (CHARINDEX( Л' ,(3oulputname)=0) SET (3outputname=(aoutputpath+i?outputname -- Создать обьект SQLServer EXEC (ahr=sp OACreate SQLDMO,SQLServer, gobject OUTPUT IF mr <> 0) BEGIN EXEC sp displayoaerrorinfo (aobject, @nr RETURN END -- Создать обьект BulkCopy EXEC (ahr-sp OACreate SQLDMO,BuikCopy. @bcobject OUTPUT IF mr <> 0) BEGIN EXEC sp displayoaerrorinfo @bcobject, ghr RETURN END -- Установить свойство OataFilePath обьекта BulkCopy EXEC @tir = sp OASetProperty №cobject, OataFilePath, (aoutputname IF mr <> 0) BEGIN EXEC sp d1splayoaerrorinfo Sbcobject, Phr RETURN END -- Указать объекту BulkCopy на необходимость создания файла с разделителем в виде знака табуляции EXEC №г - sp OASetProperty labcobject, DataFlleType, (aTAB DELIMITEO IF (№г о 0) BEGIN EXEC sp displayoaerrorinfo @bcobject, №r RETURN END -- Установить свойство LogFilePath обьекта BulkCopy EXEC 0hr = sp OASetProperty @Dcobject. LogEnePath. C°lognaiiie IF (ghr <> 0) BEGIN EXEC sp displayoaerrorinfo @bcobject. @hr RETURN END -- Установить свойство ErrorFilePath обьекта BuikCopy EXEC @hr = sp OASetProperty @bcobject. ErrorEllePatTi. (Зеггпате IF (@hr <> 0)BEGIN EXEC sp displayoaerrorinfo @bcobject. @hr RETURN END -- Установить соединение с сервером IF (gpassword IS NOT NULL) EXEC @hr = sp OAMethod @object. Connect. NULL, ©server, (pusername. gpasswc ELSE EXEC @nr = sp DAMethod ©object, Connect, NULL, ©server, ©username IF (@hr <> 0) BEGIN EXEC sp displayoaerrorinfo ©object, @hr RETURN END -- Получить указатель на коллекцию Databases объекта SQLServer EXEC @hr = sp DAGetProperty ©object, Databases, gobject OUT IF @hr <> 0 BEGIN EXEC sp displayoaerrorinfo ©object, @hr RETURN END -- Получить указатель на необходимую базу EXEC @hr = sp DAMethod ©object, Item, gobject OUT, ©dbname IF @hr <> 0 BEGIN EXEC sp disp1ayoaerrorinfo ©object, @hr RETURN END -- Получить указатель на таблицу IF (0BJECTPRCPERTY(0BJECr ID(@tab1e),IsTable)=1) BEGIN EXEC №г = sp OAMethGd ©object, Tables, ©object OUT, ©table IF ©hr <> 0 BEGIN EXEC sp displayoaerronnfo ©object, ©hr RETURN END END ELSE IF (0BJECTPR0PERTY(DBJECT lD((atable),IsV1ew)-l) BEGIN EXEC ©hr = sp DAMethod ©object, Views, ©object OUT, ©table IF ©hr <> 0 BEGIN EXEC sp disp1ayoaerrorinfo (Sobject, ©hr RETURN END END ELSE BEG IК RA1SERR0R(Source ooject r.s* bt eiir.er с tdole or view .16,:) RETURN -I END -- Вызвать кетод ExportOaia ягя з:<сгора ,!ач,.ь,/ 1аО;миы,г:редсгавлений при помети BulkCopy EXEC (Эпг = sp GAHet,hod eoPject. fxportDa:a, C=rowse/-poLed OUT, Pbcobject IF &hr <> 0 BEGIN EXEC sp disp!ayoaerrorinfo @objecE, gnr RETURN END RETURN enowsexported Heip: EXEC sp usage gobjecbname=sp expcrttable, @desc=Exports a table in a manner similar to BULK INSERl , @parameters= Stable varchar(128), -- Таблица для зксгорга @outputpath varchar(I28;=NuEL. -- Выходно!. каталог (Soutputname varchar(128)=NULL, - Выходной фа/я (тю умолчанию (atable+ ,ВСР ) gserver varchar(128)= (local), Имя сервера (ausername varchar(128) = sa, -- Икя учетной записи (по умолчанию sa) password varch,ar(128)=NULL -- Пароль учетной записи @author=Ken Henderson, Pemai T--khen@khen.cciTT , (?datecneated=I99906I4 .(adatelastcriangcd-I9990/i4, (3example=EXEC sp exporttable authors, C:\TEMP, , @returns=Number of rows exported RETURN -1 Следуйте комментариям в коде, чтобы попять, как pd5oaei процедура - она достагочно проста. Как только процедура создана, ее момно запустить так: DECLARE (Эгс int EXEC (3nc=pubs,.sp exponttable tiabе-pubs, .autnors, laoutputpa th= d: \ temp\bcp\ SELECT RowsExported=(arc RowsExported Обратите виимаиие на нримеиеине префикса pubs ирн вызове хранимой иро-цедурвк Процедура использует (Jjvhkjhho OBJECTPROPERPrO, котора>г ие работает в базе данных, отличной от текущей. Поэтому для корректной работы процедуры с объектами из других баз датиях необх(жн.мо временно переключить контекст базы на указанный в иара.метре @table. Как скттзапо в других частях книги, указание базы перед именем спсте.мпой xpami.Moii процедур!)! вре.мет!ио из.меняет контекст. Вот фу!1!<;цио1!алыИ)!Й Э1свивале1!т: 17 Лич Ю USE pubs GO EXEC (?rc-=sp exporttab1e (atable-pubs. .authors, @outputpath=d:\ temp\bcp\ GO USE master - или другую базу GO Также обратите вии.мание на использование системной хранимой процедуры sp displayoaerrorinfo. Она ие создается по умолчанию, но ее код можно найти в Books Online. Она, в свою очередь, задействует процедуру sp hexadecimai, которую также можно найти в Books Online. Обратитесь к разделу OLE Automation Return Codes and Error Information* в конце описания хранимой процедуры sp OAGetErrorInfo в Books Online для получения исходного кода обеих процедур. Задачи, которые должна выполнить процедура: О Создать объект SQLServer и соединиться с сервером. Весь обмен данны.ми с сервером через SQL-DMO происходит через это соединение. О Создать объект BulkCopy и установить значения его свойств, соответствующие типу операции массового копирования, которую требуется произвести. Мы вызовем метод ExportData объекта Table для выполнения собственно экспорта, но это требует наличия объекта BulkCopy. О Найти базу-источник при помощи извлечения ее имени из параметра @tabie и нахождения ее в коллекции Databases объекта SQLServer. О Найти таблицу-источник или представление-источник при помощи просмотра коллекций Tables ИЛ1-1 Views объекта Database. о Вызвать метод ExportData найдетюго объекта, передав методу ссылку иа ранее созданный объект BulkCopy. О Вернуть целое число, указывающее количество экспортированных строк. Вернуть -1 в случае неудачного завершения операции экспорта. Применяя автоматизацию, эта процедура способна вьиюлнить все эти задачи относительно легко. Объем Transact-SQL, необходимый для этого, не больше требуемого для аналогичной програм.мы на Delphi или Visual Basic. sp.importtable Несмотря на то что в Transact-SQL есть команда BULK INSERT для массовой загрузки даниых, для полноты здесь приведен обратный для sp exporttable код: USE master GO IF (0BJECT IDCspJmporttab1e) IS NOT NULL) OROP PROC spjmpprttable CREATE PROC sp importtab1e Stable varchar(12B). -- Таблица для импорта ©inputpath varchar(128)-NULL. -- Входной каталог завершить символом \ ©inputname varchar(12B)=NULL. -- Входной файл (по умолчанию (stab!е+.ВСР') (server varchar(128)-(local). -- Имя сервера 1 ... 45 46 47 48 49 50 51 ... 55 |
© 2004-2024 AVTK.RU. Поддержка сайта: +7 495 7950139 в тональном режиме 271761
Копирование материалов разрешено при условии активной ссылки. |