Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Базы";
Текущий архив: 2007.05.27;
Скачать: [xml.tar.bz2];

Вниз

Вставка записи при уникальном индексе.   Найти похожие ветки 

 
Ш-К   (2007-03-05 02:51) [0]

Вставляю из Delphi около 1000 записей. Таблица имеет уникальный индекс по 2 полям.
Что сделать, чтоб не ругался при вставке неуникальной записи, а просто игнорировал вставку?


 
Ш-К   (2007-03-05 02:56) [1]

Вообще-то вопрос немного в другом.
Изначально мне надо, чтобы не вставлялись в таблицу дубли. И все. Без всяких варнингов.


 
ЮЮ ©   (2007-03-05 05:35) [2]

> Вставляю из Delphi около 1000 записей.

Как это делаешь?
Перед вставкой проверь возможное наличие


 
Ш-К   (2007-03-05 06:06) [3]

Можно перед инсертом селектить, но хотелось бы проверку возложить на сервер БД.
Вставляю так:

with ADOQueryFormDocInsert do
 begin
   Close;
   SQL.Clear;
   Connection.BeginTrans;
   S := "";
   try
     for I := 0 to AFormList.Count - 1 do
     begin
       vCode  := (AFormList.Objects[I] as TaaWrapperEntryForm).FCode;
       vDocID := Director.ActiveContent.Get_ID;
       S      := "insert into FormDoc (CodeForm, Document)" +
         " values (" + IntToStr(vCode) + ", " + IntToStr(vDocID) + ");";
       SQL.Text := S;
       ExecSQL;    
     end;
   except
     Connection.RollbackTrans;
     Exit;
   end;
   Connection.CommitTrans;
 end;


От варнингов пока помогает такая штука:
try
 ExecSQL;
except
end;

Это мне не нравится.


 
ЮЮ ©   (2007-03-05 06:24) [4]

> хотелось бы проверку возложить на сервер БД

Это [Access] - сервер ? :)
С другой стороны, проверку-то он выполняет - не дает вставить дубликаты

> Это мне не нравится.

Тебе не угодишь :)
Безмолвное поведение сервера может оказаться ещё большей проблемой в другом месте, где его ругательство помогло бы локализовать реальную ошибку


 
Ш-К   (2007-03-05 07:57) [5]

Эти варнинги очень влияют на скорость вставки.


 
ЮЮ ©   (2007-03-05 08:27) [6]

> Эти варнинги очень влияют на скорость вставки.


Для увеличения скорости, избежания вставки дубликатов и прочая, предлагаю немного модифицировать процесс импорта данных:

Создаnm таблицу FormDocImport такой же структуры, но без ключей - вставка в такую таблицу будет быстрее и не вызовет ошибок.
Затем одним запросом

insert into FormDoc (CodeForm, Document)
 select i.CodeForm, i.Document
 from
   ImportDocExport i
   LEFT JOIN FormDoc fd ON i.CodeForm = fd.CodeForm AND i.Document = fd.Document
   WHERE fd.CodeForm IS NULL

залить только "новые" данные.
FormDocImport следует очищать до и/или после импорта


 
sniknik ©   (2007-03-05 08:39) [7]

ЮЮ ©   (05.03.07 06:24) [4]
> Это [Access] - сервер ? :)
ну а почему нет? вообще это конечно не сервер, движок аксесс это COM обьект, но проще всего его рассматривать (по поведению) именно как сервер, такое же ядро, удаленное и независимое от программы с которым общаешься с помощью запросов... в общем полный аналог/модель (он кстати и удаленно может работать... через RDSServer.DataFactory/RDS.DataControl, вроде тоже части jet обьекты. т.е. тот же движок).

Ш-К   (05.03.07 07:57) [5]
> Эти варнинги очень влияют на скорость вставки.
это последнее о чем тебе стоит беспокоится  в плане влияния на скорость... по коду в [3] гораздо больше влияют - использование тяжелого ADOQuery, неиспользование параметров, а пересоставление запроса для каждой вставки, не отключение контрола (есть подозрение что он визуальный), и использование "клиентских" транзакций (хотя вот это последнее под вопросом, я так никогда не делаю поэтому не знаю тонкостей поведения а те кто делал и жаловался тут на скорость тем совет поменять на запросы говорили помогал...).
ну и потом у тебя логическая ошибка, несоответствие желаемого  
> Изначально мне надо, чтобы не вставлялись в таблицу дубли. И все. Без всяких варнингов.
с кодом, в коде будет не "невставление" дублей, а невставление всего блока если есть хоть один дубль, изза транзакции (которая в данном случае не нужна вообще. имхо (не знаю конкретики твоей задачи, но по догадгам и текущему описанию...)), и того что блок try except закрывает весь цикл.


 
sniknik ©   (2007-03-05 08:47) [8]

ЮЮ ©   (05.03.07 08:27) [6]
> Для увеличения скорости, избежания вставки дубликатов и прочая
+
в промежуточную таблицу тоже заливать пакетом, из текстового файла/дбф-а и т.д. смотря откуда эти данные берутся (в AFormList они откуда?). иногда даже сформировать текстовый файл а после залить одной командой будет быстрее чем позаписьно...

но вообще надо смотреть на то сколько дублей, если один два на тысячу то такие "предварительные ласки" ничего не ускорят, смысл имеет если их много, ну половина хотябы... а то и наоборот на тысячу только одна две новые... вот тогда да, варнинги будут сильно влиять/тормозить.


 
ЮЮ ©   (2007-03-05 08:52) [9]

> движок аксесс это COM обьект

Полагаю, что речь здесь все-таки не об Access, а о mdb-файлах. На файл-сервере может и не оказаться никакого Access


 
sniknik ©   (2007-03-05 09:03) [10]

> Полагаю, что речь здесь все-таки не об Access, а о mdb-файлах
я говорил о jet, он давно уже для меня олицетворение Access ;о), а программа аксесс настолько редко исползуема, что говоря о ней специально упоминаю что это именно о программе речь.

> На файл-сервере может и не оказаться никакого Access
естественно, может не быть, нет и не надо. речь не о нем а о движке аксесс, jet. перечитай 1 абзац из [7].


 
ЮЮ ©   (2007-03-05 09:14) [11]

> [10] sniknik ©   (05.03.07 09:03)

Т.е. Access-а может и не быть, но jet присутствовать обязан? И клиентский jet работает не с mdb файлом а с "серверным" jet-ом?

Или все-же несколько клиентских jet-ов работают напрямую с серверным mdb файлом, использую заложенный в него механизм многопользовательского доступа? Т.е. так же как BDE с парадоксовскими файлами?


 
sniknik ©   (2007-03-05 09:48) [12]

> Т.е. Access-а может и не быть, но jet присутствовать обязан?
естественно. он по умолчанию практически всегда и ставится вместе с операционкой.

> И клиентский jet работает не с mdb файлом а с "серверным" jet-ом?
где я такое говорил? не тупи. рассматривалась программа и jet (1 копия), неважно где он стоит на твоей машине или на другой, по поведению это в любом случае сервер. и по умолчанию всегда используется локальный, для работы же с удаленным нужны упоминавшиеся обьекты (с ними работа по DCOM), , но их практически не используют... сложно. проще файл расшарить.


 
ЮЮ ©   (2007-03-05 10:01) [13]

Тогда не вижу никакой серверности. Работая с парадоксом в сети через BDE (такое же ядро, удаленное и независимое от программы с которым общаешься с помощью запросов... ) имею такой же "сервер", что и с mdb через Jet :)


 
sniknik ©   (2007-03-05 11:50) [14]

> Работая с парадоксом в сети через BDE
не в сети, а неважно где, даже если все локально.
открытие таблицы, эту таблицу попросту открывает как файл...
в отличие от jet (стандартный вариант рассматриваем, настройками можно изменить), который открытие таблицы в компоненте преобразовывает в запрос к ядру, и это ядро возвращает рекордсет, копию данных в памяти. так же как любой другой sql сервер. т.е. принцип работы клиент серверный а не файл сервер. и сервером здесь выступает ядро/COM обьект jet...
и дальнейшее общение идет только запросами через это ядро, BDE же может (и это в нем выгоднее) общатся/и общается с таблицами как с файлами. (есть и исключения, все зависит от провайдера данных (или как там в BDE?), но принцип у "нативе" драйверов всетаки файл серверный)

разве не видиш разницу?

да в общем неважно, можеш думать как хочеш, просто рассматривать/работать с jet как sql сервером, гораздо проще/логичнее/можно избежать кучи проблем, чем по другому, рассматривая mdb просто как файл на своей машине/в сети.


 
Sergey13 ©   (2007-03-05 11:55) [15]

> [14] sniknik ©   (05.03.07 11:50)
Я может чего не понимаю в вашем с ЮЮ споре, но не объясняется ли такая "сервероподобная" работа с аксесом тем, что MDB это однофайловая БД, в отличии от "таблично-файловых" (типа xBase).


 
sniknik ©   (2007-03-05 12:17) [16]

Sergey13 ©   (05.03.07 11:55) [15]
где спор?
я не спорю, мне вообще пофиг кто как считает (хотят сложностей/проблем... да пожалуйста), но он вроде как спрашивает, я вроде как пытаюсь обьяснить...

> но не объясняется ли такая "сервероподобная" работа с аксесом тем ...
может быть, но скорее всего нет, вернее не единственная причина. про становление/разработку ADO когдато читал, там было что писали его под MSSQL и access до кучи, jet тоже в тоже время разрабатывали (до этого был DAO. счас он часть jet, и скорее всего только для совместимости старого и остался)... ну и...,  вот как увязать совершенно разные принципы в одном продукте? ну судя по всему то что мы сейчас имеем это и есть решение от мелкософта, сделать локальный движок так чтобы работать с ним как с sql сервером. тогда не нужны дополнительные механизмы/деления на файл/клиент сервер (тем более файл устарел и отмирает) и т.д. все стало гораздо проще при таком решении.
т.е. скорее обьясняется это решением мелкосовта перейти на новое и отойти от старых технологий весде, даже там где они в принципе и не очень мешают.


 
ЮЮ ©   (2007-03-05 12:28) [17]

На низком уровне всё равно файловые операции над mdb, расположенном на другом компьютере выполняют процессы клиента ведь так? Именно в этом я и вижу главное отличие клиент-сервера, где только сервер имеет доступ к физическим данным, а клиент - к логическим, от файл-сервера, где клиент модифицирует физический файл. БДЕ API тоде не дает доступа к данным на уровне физического файла, тем не менее его сервером не называют и клянут по чём поподя :)


 
MsGuns ©   (2007-03-05 12:41) [18]

Акцесс не позволяет писать о одну таблицу одновременно нескольким пользователям, поэтому можно "подожиться" на то, что связка "проверить - добавить - перечитать" выполнится на неизмененной таблице. Хотя, можно все это "завернуть" в одну транзакцию для надежности.
Что же касается дубликатов..
"Мягкий" алгоритм должен перед Insert включать Select Key1,Key2 с проверкой наличия возвращенной записи,
"Жесткий" проверку не делает, сразу добавляя новую запись - в этом случае роль "цербера" должен выполнить сервер (Акцесс), "выплюнув" запрос с соответсвующим сообщением, "спрятать" который можно, сунув выполение вставки в защищенный блок.

В обоих случаях "тормозов" быть не может. А если они есть, то см. свою программу, не исключено, например, что переоткрытие отображаемого датасета делается не зависимо от того, успешно ли была вставлена запись.


 
sniknik ©   (2007-03-05 13:09) [19]

> На низком уровне всё равно файловые операции над mdb, расположенном на другом компьютере выполняют
> процессы клиента ведь так?
чтобы такого не было есть пара приведенных выше обьектов (+ RDS в ADO)... которые обычно никто не использует (и правильно, я пробовал, мелкософт их сделал сложными в использовании, специально имхо, чтоб активнее на mssql пересаживались ;)).

p.s. Sergey13 был прав, ты именно споришь. пытаешься "продавить" свою точку зрения притягивая чуть ли не за уши любые аргументы к теме не относящиеся, "буквоедствуеш". ну вот какая разница как там что работает на низком уровне? когда говорилось о принципе работы с самим обьектом. про взаимодействие программы с ADO jet/BDE paradox (?).
сколько бы начинающих не начинало с TADOTable/избежало проблем/тормозов если бы им вовремя сказали "работай с этим как с клиент сервером, несмотря на то что файл базы у тебя локально/доступ по расшарке, читай сразу про технологию клиент сервера, смотри примеры по нему, она jet-у гораздо ближе, чем то что ты сейчас читаешь про BDE и тупо (пока не понимаешь) переносишь на ADO".

ну раз спор, то нафик, переубеждать закостеневшие взгляды на вещи себе дороже. и бессмысленно.


 
ЮЮ ©   (2007-03-05 13:21) [20]

Споришь ты. Буквоедствуя я. :)

Используя TQuery в BDE и TAdoDataSet в ADO я лично вообще не вижу разницы в клиент-серверных приложениях ни при работе с Paradox+BDE, ни при MS SQL + BDE, ни при MS SQL+ADO. Разве что MS SQL позволяет сам гораздо больше вкусностей.


 
sniknik ©   (2007-03-05 13:37) [21]

> не вижу разницы в клиент-серверных приложениях ни при работе с Paradox+BDE, ни при MS SQL + BDE, ни при MS SQL+ADO
берешь таблицу с парой миллионов записей для каждого случая, подключаешь ее и делаешь Table1.Open в случае с Paradox+BDE, и ADOTable1.Open в случае с MS SQL+ADO (или MS SQL+Jet при стандартных настройках, про настраиваемость выше упоминал) и ты эту разницу не только увидишь ты ее компьютерными герцами прочуствуеш...
(и неважно на локальной машине парадоксовская таблица/база mdb лежит или в расшарке на сервере (mssql несколько особняком но тоже неважно где находится))

> Буквоедствуя я. :)
я всетаки склонен думать недопонимаешь.... иначе бы не пытался обьяснить.

> MS SQL + BDE
про "исключения" см. [14] второй абзац.


 
MsGuns ©   (2007-03-05 16:35) [22]

>ЮЮ ©   (05.03.07 13:21) [20]
>Используя TQuery в BDE и TAdoDataSet в ADO я лично вообще не вижу разницы в клиент-серверных приложениях ни при работе с Paradox+BDE, ни при MS SQL + BDE, ни при MS SQL+ADO.

А разница, между тем, имеется. Хоть ты ее и не видишь ;)


 
ЮЮ ©   (2007-03-06 03:02) [23]

берешь таблицу с парой миллионов записей для каждого случая, подключаешь ее и делаешь Table1.Open

TTable сюда зачем приплетать? Особенно после [19] :)

я всетаки склонен думать недопонимаешь.... иначе бы не пытался обьяснить.

Среди множества слов так и не увидел объяснения, позволивщего хоть чуть-чуть увидеть в mdb-файле в расшаренной папки намёки на сервер БД.
Я в своё время не один раз сталкивался как MS Access(95-98) напрочь убивал свои базы при совместном использовании даже 2-мя пользователями.
И чем отличается в этом отношении Paradox-овская база (1 файл или много - не тот уровень отличий).


А разница, между тем, имеется. Хоть ты ее и не видишь ;)

Я имел в виду разницы в коде с точки зрения TDataSeta-а и его методов, а не механизмов взаимодействия клиента с БД. Укажи, если такой зрячий :)

З.Ы. Почему остальные мастера БД молчат? :)


 
sniknik ©   (2007-03-06 09:14) [24]

> Среди множества слов так и не увидел объяснения, позволивщего хоть чуть-чуть увидеть в mdb-файле в расшаренной папки
> намёки на сервер БД.
естественно, ты же специально закрываешь глаза встречая такое обьяснение... а все на что не закрыл извращаеш.

итак последняя попытка (больше не будет т.к. человеку игнорирующему доводы обьяснить ничего в принципе невозможно).

во первых где я говорил что файл mdb в расшаренной папке это сервер БД? не было такого, говорилось про ядро jet, COM обьект, то что его можно рассматривать как sql сервер, по поведению, по тому как с ним работать (со всеми возможными оговорками говорилось, что это вовсе не реальный сервер, и про разные режимы упоминалось... и кстати если уж на то пошло он и парадоксом работает также. т.е. открывая джетом файл *.db будет то же поведение).

главное отличие, в принципе работы, открытие таблицы в файл серверном открывает файл и возвращает его хендл для дальнейшей работы, размер таблицы на время открытия не влияет, в клиент серверном тоже открытие таблицы считывает ее в память формирует рекордсет который передается через ядро/sql сервер на клиента (пусть даже этот клиент тут же на сервере, т.е. оба на одной машине), размер таблицы очень даже влияет на время открытия.
т.е. разница в принципах, про которую знать желательно всем, и чем раньше тем лучше. а не просто тупо заучить "sql это круто!", на все есть причины, и та о которой я говорю одна из тех которая в одном случае делает запросы выгоднее (и единственно правильным способом работы), в другом и простое открытие таблицы пойдет, и даже часто лучше пойдет чем запрос sql.

> Я имел в виду разницы в коде с точки зрения TDataSeta-а и его методов, а не механизмов взаимодействия клиента с БД.
стрелки переводишь? именно о механизме взаимодействия клиента с ядром/sql сервером у нас речь...

но в общем и в методах датасетов есть различия, например Sort возможный при работе с рекордсетом (потому как он в памяти находится) и невозможный с файлами у файл серверного метода (либо при настройках псевдо файл сервера у jet). и обратная сторона, индексы, подключение индекса возможно у файлов (если эти индексы есть конечно) и невозможно у рекордсета т.к. его индексы остались на сервере, а на клиенте их попросту нет.
(может и еще есть, но думать неохота на эту тему, т.к. это все одно придирка, очередное увиливание в нежелании признать чужую правоту)

> З.Ы. Почему остальные мастера БД молчат? :)
ну это надеюсь тебе ктонибудь другой объяснит. без меня. ;о)


 
MsGuns ©   (2007-03-06 16:16) [25]

>ЮЮ ©   (06.03.07 03:02) [23]
>Среди множества слов так и не увидел объяснения, позволивщего хоть чуть-чуть увидеть в mdb-файле в расшаренной папки намёки на сервер БД.

Действительно, скрпировал gdb кликнул на нем двойничком и получил фигу с медом. Игде там интербуз ?, - ох, дурют народ !

>Я в своё время не один раз сталкивался как MS Access(95-98) напрочь убивал свои базы при совместном использовании даже 2-мя пользователями.

А я вот не "сталкивался", а работаю периодически лет 5. И ни одного "слета" - я исключение ?

>И чем отличается в этом отношении Paradox-овская база (1 файл или много - не тот уровень отличий).

Тем, что отсутствуют как класс такие фундаментальные вещи как метаданные, бизнес-логика, транзакции, счетчики и еще ооочень много того, что есть в любом мало-мальски приличном скл-сервере (например, в Акцесе)

>Я имел в виду разницы в коде с точки зрения TDataSeta-а и его методов, а не механизмов взаимодействия клиента с БД. Укажи, если такой зрячий :)

Имеется, и именно с точки зрения самого датасета. Хотя бы сортировка по произвольному порядку без правки текста запроса и переоткрытия или тот же ReQuery. Кроме того, адошный датасет менее капризен в плане "редактируемости". Да много чего еще..


 
ЮЮ ©   (2007-03-07 05:13) [26]

[25] MsGuns ©   (06.03.07 16:16)
> Тем, что отсутствуют как класс такие фундаментальные вещи как метаданные, бизнес-логика, транзакции, счетчики и еще
> ооочень много того, что есть в любом мало-мальски приличном  скл-сервере (например, в Акцесе)

И чего такого в Paradox-е нет (из перечисленного), что есть в приличном скл-сервере Акцесе :)


> А я вот не "сталкивался", а работаю периодически лет 5. И ни одного "слета" - я исключение ?

не верю, что активно работаешь в многопользовательском режиме в приложнии "MS Access 95(98)".

> Хотя бы сортировка по произвольному порядку без правки текста
> запроса и переоткрыти

А это больше похоже на клиентскую работу с курсором. Для этого специально TClientDataSet придуман.


> Действительно, скопировал gdb кликнул на нем двойничком и получил фигу с медом. Игде там интербуз ?, - ох, дурют
> народ !

Лучше HexEditor-ом (если Блокноту не доверяешь) открыть mdb, "откорректировать" и сохранить. И пусть jet отдыхает :)

[24] sniknik ©   (06.03.07 09:14)

> главное отличие, в принципе работы, открытие таблицы в файл серверном открывает файл и возвращает его хендл для дальнейшей
> работы. в клиент серверном тоже открытие таблицы считывает ее в память формирует рекордсет

Работая с MS SQL + BDE я, по твоей логиге, работаю не с сервером, а с файлом только потому, что БДЕ сохраняет курсор в файл, а не хранит в памяти?
Да и hDBIDb это хэндл всё-таки для логических оперций над таблицей БД, а не файлом ОС.
Jet-у, можно подумать хендл файла не нужен и изменения он вносит божественным способом, просто показав mdb-файлу текст запроса.
То что BDE API открыт на уровне доступа к файлу БД, а JET-а - на уровне доступа к курсору, говорит лишь о степени закрытости технологий второго.

Главное отличие сервера БД от файла БД, ИМХО, предостоавление только "логических" данных и полное отсутвие доступа клиентского приложения к физическому файлу. Сам Сервер БД на серевере является уже клиентом, работющим с файлом. Как и любой Embeded "сервер" - это просто "навороченный" TDBF.


 
sniknik ©   (2007-03-07 08:42) [27]

> TTable сюда зачем приплетать? Особенно после [19] :)
потому что на нем ВИДНО, по разнице работы тейблов в разных технологиях хорошо видна разница в их принципах.

> Для этого специально TClientDataSet придуман.
это уже не BDE, это уже мидас. часть технологии трехзвенок, сервер которого кстати тоже можно рассматривать как своеобразный sql сервер... даже при том, что написан он не какойто конторой а самим программистом. (и даже при том что ни одного sql запроса им не было использовано... просто в этом случае можно принять что все они были простые на полное открытие таблиц)

...

ну и т.д. каждое притянутое за уши "доказательство" опровергать смысла как уже решили нет... (сколько не говори, а когда откидывается все что обьясняет, и берется исключение (о котором и так говорилось что это работает несколько по другому) для контраргументов. ну это о чемто да говорит)


 
MsGuns ©   (2007-03-07 21:04) [28]

>ЮЮ ©   (07.03.07 05:13) [26]
>И чего такого в Paradox-е нет (из перечисленного), что есть в приличном скл-сервере Акцесе :)

Всего перечисленного.

>не верю, что активно работаешь в многопользовательском режиме в приложнии "MS Access 95(98)".

"Блажен кто верует и горе тому, кто не верит" (с)

>А это больше похоже на клиентскую работу с курсором. Для этого специально TClientDataSet придуман.

Только при чем тут вообще парадокс ? Или мы творог из вареников добываем ?

>sniknik ©  

Коля, тут, похоже, тот случай, когда бисер следует поберечь ;)


 
ЮЮ ©   (2007-03-09 09:28) [29]

>sniknik ©  
>Коля, тут, похоже, тот случай, когда бисер следует поберечь ;)

Угу, экономьте, помечите перед собой :)



Страницы: 1 вся ветка

Форум: "Базы";
Текущий архив: 2007.05.27;
Скачать: [xml.tar.bz2];

Наверх




Память: 0.57 MB
Время: 0.05 c
6-1163753017
Layner
2006-11-17 11:43
2007.05.27
TIdTCPServer - узнать IP или имя кто к нему приконнектился...


15-1178010982
SerJaNT
2007-05-01 13:16
2007.05.27
Drupal


2-1178874455
Marat
2007-05-11 13:07
2007.05.27
Процедура


2-1178806134
Гость____
2007-05-10 18:08
2007.05.27
Редактор Delphi


6-1163767232
Layner
2006-11-17 15:40
2007.05.27
Как грамотно отключить от IdTCPServer всех IdTCPClient





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский