Страницы

Поиск по вопросам

Показаны сообщения с ярлыком база-данных. Показать все сообщения
Показаны сообщения с ярлыком база-данных. Показать все сообщения

среда, 15 апреля 2020 г.

Размещение созданной БД SQLite в проекте под Android

#android #java #sqlite #база_данных

                    
Здравствуйте. Пишу небольшой справочник, в основе которого будет база данных. Файл
БД создан на стороне средствами специального ПО. Данный файл нужно подгрузить в приложение
Android. Каким образом размещать файл, каков путь для доступа к внедряемой БД, какие
методы следует реализовать для обеспечения подключения и дальнейшей работы с данной
БД в приложении?    


Ответы

Ответ 1



Если ещё не читали, то будет полезна статья на Хабре «Правильная работа с БД в Android». Там же есть ссылка на тему прикрепления БД. Сам давно уже использую этот подход. Меня устраивает. Обсуждение тонкостей также производилось в вопросе «Правильная работа с SQLite-базой в Android».

Ответ 2



Базу на флешку. В приложении сделать выбор пути к базе.

понедельник, 13 апреля 2020 г.

Методы сортировки смешанных данных (текст + числа)

#база_данных #сортировка #алгоритм

                    
Какие есть способы сортировки данных типа:

Профессиональное училище № 21
Профессиональное училище № 30
Профессиональное училище № 120

или:

pgAdmin v1.8.4
pgAdmin v1.10.5
pgAdmin v1.12.3

Есть ли возможность сделать это на уровне БД?
Вопрос касается не только приведенных примеров, но вообще любых возможных вкраплений
в текстовые поля чисел.    


Ответы

Ответ 1



имхо у вас проблема не с сортировкой данных а с проэктированием СУБД. значения то неатомарные, - посему должна иметь место оптимизация и разбиение данных на 2 поля: имя + номер или продукт + версия если вы не слышали ничего про реляционные СУБД (втч. про нормальные формы) есть и для вас пару вариантов: для всех полей которые являются комплексными нужно добавить по одному numeric полю в таблицу. и на вставку/обновление повесить триггер который будет для каждого такого поля заполнять соответствующие им поля _order. которые и будут использоватся для сортировки. или же сами можете заполнять при вставке. (имеет смысл хранить эти данные в отдельной таблице) можно добавить функцию которая будет подсчитывать order для сортировки на лету. выглядеть это будет как-то так: 1) select x.afield from xtable x order by get_order (x.afield) или 2) select x.afield from xtable x order by get_order ('xtable', 'xfield', x.afield) настройки для функции get_order могут хранится в какой-то отдельной таблице. в первом примере вам придется автоматически определять шаблон который использовать для определения порядка следования записи, в другом примере вы сможете с помощью if elseif... использовать алгоритм в зависимости от входных данных. первый вариант более предпочтительный с точки зрения performance. а правильный, - оптимизация структуры СУБД UPDATE: с одной стороны полное имя учебного заведения это вроде как-бы единое значение. но это только на первый взгляд. "профессиональное" (опциональный префикс, - можно игнорировать) "училище" - тип учебного заведения (академия, институт, университет) может быть использовано для сортировки "№ 43" - номер учебного заведения. "Санкт Петербурга" - явно же город. "имени" васи пупкина - даж незнаю как атрибут назвать но "имени" явно можно использовать для фильтра, - только есть ли смысл, - хз. далее логически анализируем данные: номер учебного заведения + его тип = уникальная комбинация (в пределах одного города) учебное заведение может быть расположено только в одном городе, во всех остальных будут филиалы. хотя называтся могут одинаково. т.е комбинация этих 3х полей не будет уникальной. в результате получается таблица следующего содержимого: id // уникальный id type, // профессиональное училище / университет / академия. можно вынести в отдельную таблицу number, // порядковый номер. его в принцыпе может и не быть. (это надо учесть в сортировке) dedication_id // поле которое будет хранить ссылку на id человека которому посвящено. если null - то никому не посвящено. null тоже можно учесть при сортировке foundation_date // время когда было создано учебное заведение. имхо это важное поле. description // или full_name/display_name - полное имя заведения, то которое вы будете отображать пользователю. и которое никогда не будет участвовать в сортировке. location_id // ссылка на таблицу с местоположениями (ессно будет содержать город) p.s. пожалуй еще лучше было бы создать отдельную таблицу отделения или филиалы. привязанную к конкретному учебному заведению. где каждый отдельный филиал имеет свой конкретный адресс. что позволит хранить данные независимые от других филиалов. напр: количество студентов/наличие кафедр/специальностей итд итп таблица dedication id, // уникальное id prefix, // его величество name, // василий пупкин ^^ таблица нужна, т.к. одному ученому может быть посвящено больше чем 1 заведение. p.s.s если обобщить одной фразой работу с субд: легко проэктировать = сложно работать и наоборот.

суббота, 11 апреля 2020 г.

Нормальные формы БД

#база_данных #sql

                    
Добрый день! Прошу оценить мое понимание темы.
1 форма : в таблицах отсутствуют столбцы такие, что они состоят из избыточных, повторяющихся(из
строки в строку) данных. 
Как привести: разделить такие столбцы на несколько(по количеству повторяющихся записей)
2 форма : 1я форма + в таблицах есть столбцы такие, что они не являются ключами,
но имеют функциональную зависимость с остальными столбцами(задав значение таких столбцов,
получим остальные).
Как привести: разделить таблицу на несколько(по количеству потенциальных ключей,
в итоге в каждой таблице будет только 1 первичный ключ).
3 форма : 2я форма + в каждой таблице отсутствуют неключевые столбцы, которые зависят
друг от друга. если изменить значение в таком столбце, необходимо изменить и в сопряженных.
Как привести: так же как и 2ю, разделив по зависимым столбцам и сделав их первичными
ключами.
Буду благодарен за комментарии.    


Ответы

Ответ 1



1НФ = Отношение -> 4 фундаментальных свойства. 2НФ = 1НФ + нет неключевых атрибутов, зависящих от части ключа. 3НФ = 2НФ + нет взаимозависимых неключевых атрибутов.

Схема БД для учета проведенных конференций

#mysql #база_данных #проектирование

                    
Проектирую бд для системы учета проведения НИРС в ВУЗах.

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

К примеру у меня есть 1 человек, который создает приказ (Подтверждающий) и 2 человека
которые утверждают (Удтверждающие), тогда в таблице Приказы будет 2 записи, в которых
будут повторяться поля Тема приказа, Номер приказа, Дата приказа, Код подтверждения,
и будут отличаться в 2 записях только поле Код утдверждения.

Как можно перестроить схему, чтобы избавиться от этого изьяна, или есть возможность
хранить в поле таблицы массив данных(что врядли)?


    


Ответы

Ответ 1



будет происходить избыточность данных да, при описанной схеме работы факт и момент подписания (а в идеале — и отзыва) подписи следует фиксировать в отдельной таблице, связанной с таблицей приказов и таблицей(-ами) полномочий. но если все приказы соответствуют шаблону «три подписи», то, вероятно, проще будет добавить в таблицу приказов три соответствующих поля, содержащих либо null, либо id подписавшего/утвердившего. а в принципе, вопросы «оцифровывания» документооборота вообще, и фиксации подписаний-утверждений-согласований-отклонений в частности — тема достаточно обширная. в наиболее полном варианте, например, обязательно следует учитывать тот факт, что полномочия подписания предоставляются лишь на время. т.е. начинать надо с грамотной постановки задачи, в которой чётко определить, насколько «оцифрованный» документооборот будет упрощён относительно реального.

четверг, 9 апреля 2020 г.

Как осуществить поиск похожего текста в MySQL?

#mysql #база_данных #текст #выборка

                    
Дано: таблица с полями id и txt, где txt - небольшая статья, пост или комментарий,
содержащий HTML, примерный объем записи - 2-10 кб, всего записей 100к-1млн.

Нужно извлечь группы записей, в которых текст приблизительно похож, т.е. совпадать
процентов на 80-90, т.к. идентично равных строк в БД нет.

Позволяют ли существующие механизмы БД осуществить такую выборку, и как это сделать?

UPD: (очень близко) есть ли аналог пхп-шного similar_text() в mysql? Скорость выполнения
запроса не имеет значение.
    


Ответы

Ответ 1



Как было сказано выше, можно попробовать расстояние Левенштейна. Еще один пример реализации для mysql тут: http://www.artfulsoftware.com/infotree/qrytip.php?id=552 Можно сделать адаптированный вариант с этого примера: CREATE FUNCTION levenshtein( s1 text, s2 text ) RETURNS INT DETERMINISTIC BEGIN DECLARE s1_len, s2_len, i, j, c, c_temp, cost INT; DECLARE s1_char CHAR; -- max strlen=255 DECLARE cv0, cv1 VARBINARY(10240); SET s1_len = CHAR_LENGTH(s1), s2_len = CHAR_LENGTH(s2), cv1 = 0x00, j = 1, i = 1, c = 0; IF s1 = s2 THEN RETURN 0; ELSEIF s1_len = 0 THEN RETURN s2_len; ELSEIF s2_len = 0 THEN RETURN s1_len; ELSE WHILE j <= s2_len DO SET cv1 = CONCAT(cv1, UNHEX(HEX(j))), j = j + 1; END WHILE; WHILE i <= s1_len DO SET s1_char = SUBSTRING(s1, i, 1), c = i, cv0 = UNHEX(HEX(i)), j = 1; WHILE j <= s2_len DO SET c = c + 1; IF s1_char = SUBSTRING(s2, j, 1) THEN SET cost = 0; ELSE SET cost = 1; END IF; SET c_temp = CONV(HEX(SUBSTRING(cv1, j, 1)), 16, 10) + cost; IF c > c_temp THEN SET c = c_temp; END IF; SET c_temp = CONV(HEX(SUBSTRING(cv1, j+1, 1)), 16, 10) + 1; IF c > c_temp THEN SET c = c_temp; END IF; SET cv0 = CONCAT(cv0, UNHEX(HEX(c))), j = j + 1; END WHILE; SET cv1 = cv0, i = i + 1; END WHILE; END IF; RETURN c; END; CREATE FUNCTION levenshtein_ratio( s1 text, s2 text ) RETURNS INT DETERMINISTIC BEGIN DECLARE s1_len, s2_len, max_len INT; SET s1_len = LENGTH(s1), s2_len = LENGTH(s2); IF s1_len > s2_len THEN SET max_len = s1_len; ELSE SET max_len = s2_len; END IF; RETURN ROUND((1 - LEVENSHTEIN(s1, s2) / max_len) * 100); END; Выбрать попарно похожие строки так: select t1.id, t1.txt, t2.id, t2.txt from table1 t1 join table2 t2 on t2.id <> t1.id and levenshtein_ratio(t1.txt, t2.txt) > 80 Как разбить результат выборки на группы, придется подумать. По работе, если кратко, то алгоритм считает количество замен/добавлений символов в текст, чтобы получить полностью схожие записи. Но главная проблема - алгоритм осуществляет посимволный перебор, что является довольно затратным. А теперь если учесть, что длина текста 2-10 кб и до 1 млн. записей, то база будет просто умирать от такой "аналитики" (а не забывайте, что главная задача базы - осуществлять хранение и доступ к данным, но никак не реализовывать сложные вычислительные алгоритмы). Поэтому я бы рекомендовал, пока не поздно, подумать над тем, чтобы вынести реализацию за пределы базы. Можно найти множество "быстрых" реализации вычисления расстояния Левенштейна практически на всех языках. При реализации предложил бы делать какую-то предварительную фильтрацию, например по длине текста, т.е. если длина не совпадает на 80%, то сравнение даже не проводить, т.к. даже на производительных машинах сравнение таких объемов текста уже будет заниматься ощутимое время.

Ответ 2



Вы можете решить данную задачу с помощью использования хранимых процедур. Например так: CREATE PROCEDURE dbo.spSimil_FirstNameLastName @str1 nvarchar(max), @threshold float AS SET NOCOUNT ON SELECT * FROM (SELECT dbo.fnSimil(@str1, Person.Person.FirstName + N' ' + Person.Person.LastName) AS Simil, * FROM Person.Person) AS T WHERE T.Simil >= @threshold ORDER BY T.Simil DESC; Процедура вызывается следующим образом: EXEC dbo.spSimil_FirstNameLastName N'John Adams', 0.75 Подробнее можно узнать тут: http://www.accessmvp.com/tomvanstiphout/simil.htm Для решения вашей задачи можно попробовать прибегнуть к расстояние Левенштейна: ссылка на реализацию для mysql: https://github.com/ifsnop/damlev

Работа с БД Access в Visual Studio 2015. Создание многопользовательской БД

#c_sharp #база_данных #visual_studio #access

                    
Имею БД Access и прогу на C# работающую с ней. Пока все тестил в монопользовательском
режиме. Но сама программа должна выполнять роль клиентского приложения для офиса кадастрового
управления, и поэтому имеет место много пользовательское обращение к одной БД. Как
избежать проблем с одновременными подключениями нескольких пользователей, обращение
к одним данным, ведь явно будет ужасная потеря целостности.
    


Ответы

Ответ 1



Потери целостности, по крайней мере на уровне базы, не будет - Аccess это все-таки база данных, и она обеспечивает целостность всех данных, включая внешние ключи. И да, она полноценно поддерживает транзакции. Т.е. при работе из .NET она практически ничем не отличается от SQL Server, кроме строки соединения. Но вам придется пересмотреть ваш код на предмет предположений, которые могут быть ложными в случае одновременной работы нескольких пользователей - например, если пользователи будут активно удалять данные - то стоит аккуратно обрабатывать случаи открытия их для отображения. Единственная реальная проблема с Access - это ограничение на 10 одновременных подключений. Что может стать очень серъезной проблемой при найме 11-го сотрудника :)

Ответ 2



Из вопроса не совсем понятно, как вы собираетесь обеспечивать многопользовательский режим -- то ли это трёхзвенное приложение (т.е. есть middle layer в виде application server), то ли просто клиент-сервер. Предполагаю второе. Но в случае с MS Access тут особая ситуация -- фактически это файл-сервер. Я в своё время учавствовал в создании приложений, которые используют таким образом .mdb базу. База выкладывается на файловую шару, при подключении с клиента указывается путь к файлу на шаре, естественно, у всех участников должны быть права как на шару, так и на файл. Jet-драйвер корректно обрабатывает блокировки при одновременном доступе к таблицам, тут проблем нет. Но из-за того что это файл-сервер, производительность может проседать. За чем стоит следить: Размер базы. Если я правильно помню, есть верхний предел размера файла -- кажется, 2 ГБ. Соответственно, ничего пожирающего место, такое как документы в виде полей итп хранить в базе не стоит. Старые данные после удаления остаются в файле базы -- видимо, для ускорения операции удаления. Поэтому, время от времени нужно выполнять чистку базы (Compact/Repair). Для этой операции нужен монопольный доступ к файлу базы. Про не более 10 подключений -- https://support.microsoft.com/en-us/kb/154869 -- это только для 1.1, 2.0, 2.5; для Jet 3.0 уже можно больше. Но ещё может быть ограничение на количество подключений к шаре. Но в любом случае, надо понимать, что файловая БД -- это только для небольших задач и малого числа пользователей.

Подключение к базе данных. Когда создавать и сколько ему жить в веб-приложении?

#база_данных #aspnet #aspnet_mvc #http #веб_программирование

                    
Когда создавать подключение к базе данных?


На каждый запрос к базе
На каждый HTTP-запрос
Глобально в рамках домена - от старта приложения до его смерти


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

Третий - сократит оверхед на подключениях, особенно если БД вынесена на отдельный
сервер, но лишится плюсов первых двух.

Так что же лучше и в каких случаях стоит применять? Интересно это как по поводу чистого
ADO.NET, так и EF (если под "подключением" мы будем понимать наследника DbContext).
По поводу последнего в туториалах в интернете рассуждают о разнице между п.1 и п.2,
но не п.3. Почему?
    


Ответы

Ответ 1



Если у программиста возникает такой вопрос, то ему стоит использовать Entity Framework, по тому, что в данном случае фреймворк окажется умнее программиста, который своими попытками оптимизации с наибольшей вероятностью сделает только хуже. Во первых, DbContext, это Unit of Work(как и ISession в NHibernate) Наличие одного DbContext для всего приложения - плохая идея. Единственная ситуация, где это имеет смысл, когда у вас есть однопоточное приложение и база данных, которая используется исключительно этим экземпляром приложения. DbContext не поточно-безопасный, а так же DbContext кэширует данные, по этому вы быстро получите не актуальный кэш. Все это приведет к различным проблемам, когда несколько пользователей/приложений будут работать с этой базой данных одновременно. По этому если у вас не вышеописанная ситуация, то вам лучше инжектить DbContext в каждую задачу. Создавать же контекст на каждый запрос не лучший вариант с точки зрения производительности. Во первых при подключении происходит аутентификация и авторизация, во вторых вы теряете преимущества благодаря кешированию. Другими словами, вам нужно выделять DbContext на каждую бизнес-задачу.

вторник, 7 апреля 2020 г.

выборка из базы данных строк с нарушением последовательности

#sql #база_данных #oracle #plsql

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

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

Т.е., баланс не соответствует нужному числу с учетом суммы операций.

И еще найти такие строки, по которым дата операции с меньшим номером больше даты
операции с большим номером. 
    


Ответы

Ответ 1



Вы не привели структуру таблиц и данные. Применим экстрасенсорные способности. Структура таблицы такая: create table table1( usr_id int, -- Клиент opnum int, -- Порядковый номер операции, начиная с 1 opval int, -- Сумма операции balance int, -- Текущий баланс dt date -- Дата операции ); Баланс в любой строке равен сумме всех операций по данному клиенту с первой по текущую. Номера операций идут подряд +1 к предыдущей записи данного клиента, начиная с 1. Тестовые данные: insert into table1 values(1,1,100,100,sysdate-12); insert into table1 values(1,2,100,200,sysdate-11); insert into table1 values(1,3,-30,170,sysdate-9); -- Ошибка даты insert into table1 values(1,4,300,470,sysdate-10); -- Ошибка номера, ошибка суммы insert into table1 values(2,1,100,100,sysdate-12); insert into table1 values(2,3,100,200,sysdate-11); -- Пропущен номер операции "2" insert into table1 values(2,4,100,300,sysdate-10); insert into table1 values(2,5,50,350, sysdate-9); insert into table1 values(2,6,-150,200,sysdate-8); insert into table1 values(2,7,100,250,sysdate-7); -- Ошибка в сумме Запрос: select * from ( select a.*, (lag(opnum,1,0) over(partition by usr_id order by dt))+1 n_opnum, -- Ожидаемый номер sum(opval) over(partition by usr_id order by dt) n_balance -- Ожидаемая сумма from table1 a order by usr_id,dt -- Для наглядности, на правильность работы не влияет ) where n_opnum!=opnum -- Номер операции не соответствует or n_balance!=balance -- Сумма не соответствует Результат: USR_ID OPNUM OPVAL BALANCE DT N_OPNUM N_BALANCE 1 4 300 470 28.01.2016 18:27:37 3 500 1 3 -30 170 29.01.2016 18:27:37 5 470 2 3 100 200 27.01.2016 18:27:37 2 200 2 7 100 250 31.01.2016 18:27:37 7 300 Вот примерно так. Используются оконные функции, незаменимые в таких случаях. lag(opnum,1,0) дает значение поля opnum из предыдущей записи в окне, 0 - для первой записи в окне. sum(opval) over(order by) - нарастающая сумма opval в окне. Окно в таких функциях можно задавать различными способами. В данном случае мы используем partition by что бы окно было в пределах одного клиента и применяем order by для указания порядка операций в пределах клиента.

суббота, 4 апреля 2020 г.

Как правильно организовать базу данных

#база_данных #ruby_on_rails #activerecord

                    
Столкнулся с такой проблемой.
У отелей есть много услуг (например трансфер, парковка, интернет и т.д.), так же
у каждой комнаты в отеле могут быть разные услуги (минибар, балкон, вид на море/парк
и т.д.).
Получается что объект (отель или комната) предоставляют услуги. Связь многие ко многим.

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



А как связать модели?

class Service < ActiveRecord::Base
  has_many :service_in_object
  has_many :hotels, through: :service_in_object
end

class ServiceInObject < ActiveRecord::Base
  belongs_to :object #хмм
  belongs_to :service
end

class Hotel < ActiveRecord::Base
    has_many :rooms

  has_many :service_in_object
  has_many :service, through: :service_in_object
end

class Room < ActiveRecord::Base
    belongs_to :hotel

  has_many :service_in_object
  has_many :service, through: :service_in_object
end


Как правильно это организовать?
    


Ответы

Ответ 1



У вас получается полиморфная связь, которую нужно ввести при помощи ключевого слова polymorphic. Если не возражаете, я немного переделаю таблицу service_in_objects, чтобы избавиться от object - не очень хорошее название, давайте сделаем serviceable. Миграции для таблиц могут выглядеть следующим образом create_table :hotels, comment: "Оттели" do |t| t.string :title, comment: "Название" end create_table :rooms, comment: "Комнаты" do |t| t.string :title, comment: "Номер" t.integer :hotel_id, comment: "Внешний ключ для связи с оттелем" end create_table :services, comment: "Сервисы" do |t| t.string :title, comment: "Название" end create_table :service_in_objects, comment: "Промежуточная cвязующая таблица" do |t| t.integer :service_id, comment: "Внешний ключ для связи с сервисом" t.integer :serviceable_id, comment: "Внешний ключ для связи с оттелем или комнатой" t.string :serviceable_type, comment: "Внешний ключ для связи с оттелем или комнатой" end Тогда модели с учетом полиморфной связи через промежуточную таблицу service_in_objects могут принять следующий вид class Service < ActiveRecord::Base has_many :service_in_objects has_many \ :rooms, through: :service_in_objects, source: :serviceable, source_type: 'Room' has_many \ :hotels, through: :service_in_objects, source: :serviceable, source_type: 'Hotel' end class ServiceInObject < ActiveRecord::Base belongs_to :service belongs_to :serviceable, polymorphic: true end class Hotel < ActiveRecord::Base has_many :rooms has_many :service_in_objects, as: :serviceable, dependent: :destroy has_many :services, through: :service_in_objects end class Room < ActiveRecord::Base belongs_to :hotel has_many :service_in_objects, as: :serviceable, dependent: :destroy has_many :services, through: :service_in_objects end Убедиться в том, что полиморфная связь работает, можно при помощи сидов (db/seed.rb): ActiveRecord::Base.connection.execute('TRUNCATE hotels'); ActiveRecord::Base.connection.execute('TRUNCATE rooms'); ActiveRecord::Base.connection.execute('TRUNCATE services'); ActiveRecord::Base.connection.execute('TRUNCATE service_in_objects'); services = [{title: 'internet'}, {title: 'parking'}, {title: 'service1'}] Service.create services hotels = [{title: 'mariot'}, {title: 'hilton'}] Hotel.create hotels Hotel.all.each do |h| h.rooms.create [{title: '1'}, {title: '2'}, {title: '4'}] h.services << [Service.all.sample, Service.all.sample] h.save end Room.all.each do |r| r.services << [Service.all.sample, Service.all.sample] r.save end В реальном проекте настоятельно рекомендуется покрыть тестами хотя бы связи - у вас примере идущем с вопросом явные ошибки с единственным/множественным числом - тесты вас сильно выручат на данном этапе. Напортачить в связях не сложно, модели будут работать и со сломанными связями, только воспользоваться ими не получится и при этом сообщения об ошибках на сломанных связях не совсем очевидны. Обратите внимание: Связь belongs_to - всегда единственное число, has_many - всегда множественное число. Название таблиц - всегда множественное число, название моделей - всегда единственное число.

четверг, 2 апреля 2020 г.

Поиск даты в базе данных без учёта доли секунд

#c_sharp #база_данных #entity_framework

                    
Здравствуйте. В моём приложении есть база данных. Есть таблица с колонкой типа DateTime.
В code-behind при создании объекта есть свойство Date типа DateTime. Данное свойство
я инициализирую таким образом: Date = DateTime.Now. Для работы с базой данных в code-behind
я использую технологию Entity Framework, подход к проектированию приложения Model First.

Далее, как только я сохраняю информацию в базу данных, у меня в БД у этой колонки
(Date) записывается дата, и у этой даты есть доли секунды, например: 2018-03-18 15:43:00,667.

Как сделать так, чтобы поиск даты был без учёта доли секунды, если это возможно,
конечно? Например, есть две даты: 2018-03-18 15:43:00,667 и 2018-03-18 15:43:00,122.
В приложении есть фильтр, я указываю значение Вс, 18 мар 2018 15:43:00 GMT и мне нужно,
чтобы вот эти две даты выводились в качестве результата поиска.

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


Ответы

Ответ 1



"Проверка на равенство без долей секунд" — это проверка на попадание в диапазон значений. DateTime dateFrom = GetRoundDateFromInput(); DateTime dateTo = dateFrom.AddSeconds(1); db.Foos.Where(f => dateFrom <= f.Date && f.Date < dateTo);

вторник, 31 марта 2020 г.

BackUp БД postgresql через pg_dump не работает при вызове команды из Spring

#java #база_данных #postgresql #spring #kotlin


Дано:

БД postgresql на Mac. В ней есть данные и я могу сделать BackUp из консоли вызвав
/Library/PostgreSQL/10/bin/pg_dump -U db_user_name -w -c -f my_db_name.sql my_db_name,
что создаст файл my_db_name.sql в папке где я вызываю команду.

Задача:

Настроить периодический BackUp БД через Spring.

Проблема:

При вызове вышеуказанного скрипта программно получаю ошибку Файл не найден

Вопрос:

Как же это реализовать? Кажется, проблема в правах доступа к файлам/папкам, но непонятно
какая именно и как узнать конкретно.

Пробовал:

Пробовал указывать абсолютный путь типа {ПУТЬ_К_ПРОЕКТУ_СПРИНГА}/my_db_name.sql или
/Users/myusername/my_db_name.sql - не помогает.

Код:

@Scheduled(cron = "0 * * * * *")
fun backUpDb() {
    val executeCmd = "/Library/PostgreSQL/10/bin/pg_dump -U $dbUserName -w -c -f
$database.sql $database"

    val runtimeProcess: Process
    try {
        val pb = ProcessBuilder(executeCmd)
        pb.redirectOutput(Redirect.INHERIT)
        pb.redirectError(Redirect.INHERIT)
        runtimeProcess = pb.start()
        val processComplete = runtimeProcess.waitFor()

        if (processComplete == 0) {
            println("Backup created successfully")
        } else {
            println("Could not create the backup")
        }
    } catch (ex: Exception) {
        ex.printStackTrace()
    }
}


Лог:

java.io.IOException: Cannot run program "/Library/PostgreSQL/10/bin/pg_dump -U db_user_name
-w -c -f my_db_name.sql my_db_name": error=2, No such file or directory
    at java.lang.ProcessBuilder.start(ProcessBuilder.java:1048)
    at ru.scp.quiz.service.quiz.QuizServiceImpl.backUpDb(QuizServiceImpl.kt:75)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.springframework.scheduling.support.ScheduledMethodRunnable.run(ScheduledMethodRunnable.java:65)
    at org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:54)
    at org.springframework.scheduling.concurrent.ReschedulingRunnable.run(ReschedulingRunnable.java:93)
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
    at java.util.concurrent.FutureTask.run(FutureTask.java:266)
    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:180)
    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    at java.lang.Thread.run(Thread.java:748)
Caused by: java.io.IOException: error=2, No such file or directory
    at java.lang.UNIXProcess.forkAndExec(Native Method)
    at java.lang.UNIXProcess.(UNIXProcess.java:247)
    at java.lang.ProcessImpl.start(ProcessImpl.java:134)
    at java.lang.ProcessBuilder.start(ProcessBuilder.java:1029)

    


Ответы

Ответ 1



Проблема оказалась в том, что команда в одной строке не распознаётся и надо составлять массив из каждой её части и тогда оно работает. Т.е. надо команду в массив превратить при передаче ProcessBuilder-у: val pb = ProcessBuilder(executeCmd.split(" "))

воскресенье, 29 марта 2020 г.

Логика индексов

#sql #база_данных #oracle


Есть такая таблица

CREATE TABLE my_table (
  .......
  f1 NUMBER NOT NULL,
  f2 NUMBER NOT NULL,
  ........
);


поле f1 почти уникально. В таблице может порядка 50 записей с одинаковым f1 при общем
числе записей ~100 000

поле f2 повторяется очень часто. В таблице не более 10 различных значений f2

К этой таблице бывают запросы двух типов

SELECT * FROM my_table WHERE f1 = :val1 AND f2 = :val2


и

SELECT * FROM my_table WHERE f2 <> 0
SELECT * FROM my_table WHERE f2 = 0


(сравнение идет только с нулем и только на равно/не равно)

Вопрос какой лучше индекс создать


один составной: (f2, f1)
два простых: (f1), (f2)
составной и простой: (f1, f2), (f2)

    


Ответы

Ответ 1



Один индекс, только по f1. Индекс, по которому надо читать существенную часть таблицы - бесполезен. Сильно дешевле обойти всю таблицу целиком последовательным чтением. Планировщик запросов это знает. Как следствие вы можете сделать индекс по f2, вы будете тратить ресурсы на его хранение и поддержание актуальности, но он просто не будет использоваться. Или, что тоже гипотетически возможно и что ещё хуже: будет использоваться, но вместо ускорения работы превратит простое последовательное чтение в очень много операций случайного чтения сначала прыгая по индексу, потом по таблице за данными. Дополнительно отфильтровать некоторые из 50 строк обычно не стоят того, чтобы раздувать размер индекса. Как по хранению на диске, так и в кэше в памяти. Для маленькой таблицы в 100 тыс. записей, впрочем, не принципиально. Если ваша СУБД умеет частичные (partial) индексы - то может иметь смысл сделать индекс по f2 с исключением наиболее частых значений. Вероятно, у вас большинство строк подходят либо под f2 <> 0 либо под f2 = 0.

Ответ 2



Кроме индекса по f1, я бы еще попробовал построить bitmap index по f2 и посмотреть какие планы строит оптимизатор. Есть неплохой шанс, что запросы вида: SELECT * FROM my_table WHERE f2 <> 0 SELECT * FROM my_table WHERE f2 = 0 будут работать быстрее с использованием bitmap индекса по f2.

четверг, 19 марта 2020 г.

Как описать граф, где важны только рёбра?

#графы #база_данных


Планирую проект, где будет множество данных о связях между очередными двумя узлами,
и эти связи и их многочисленные свойства — главная информация, с которой вся работа.
Можно сказать, что есть граф, у которого узлы лишь идентифицируются как-то, чтобы
не перепутать, а область интереса это рёбра.
Как бы вы стали описывать и хранить такие данные?
Варианты, которые пока приходят на ум:

реляционная БД, таблица нод, таблица связей: node1id, node2id, json_properties
какая-то специфическая, может, не реляционная бд, заточенная под описание графов?

Задачи: хранить, добавлять новые связи, определять, связаны ли две ноды через цепочку
связей?    


Ответы

Ответ 1



Если я правильно понял задачу, то, как вариант - neo4j, статья на хабре

Ответ 2



Возможно ответ на Ваш вопрос Язык Анимо.

Ответ 3



Можно попробовать задать переменными PHP координаты и эти переменные в MySQL, или если человек рисует граф в онлайне то просто в PHP

SyntaxError: Non-ASCII character '\xd1'

#python #access #база_данных #запрос #sql


Написал следующий код
conAcc = pyodbc.connect('DRIVER={Microsoft Access Driver (*.mdb, *.accdb)};DBQ=D:\ThirdTask\Northwind.accdb')
SqlAccess=conAcc.cursor();
SqlAccess.execute(sql.sql_count_record_clients);
CountOfRecords=SqlAccess.fetchone();
conAcc.close();

где в модуле sql.py есть строка 
sql_count_records_clients='''SELECT COUNT(*) FROM "Список клиентов"'''

В результате на эту строку в sql.py выдает ошибку
Traceback (most recent call last):
  File "D:\ThirdTask\connect.py", line 5, in 
    import json,sqlite3,sql
  File "D:\ThirdTask\sql.py", line 48
SyntaxError: Non-ASCII character '\xd1' in file D:\ThirdTask\sql.py on line 48, but
no encoding declared; see http://www.python.org/peps/pep-0263.html for details

Что необходимо слелать, чтоб ошибка исчезла?    


Ответы

Ответ 1



Python 2.x по умолчанию читает исходники как ascii, и если видит октеты больше 127, то кричит вот этим самым SyntaxError. Чтобы указать Python в какой кодировке записан файл, нужно в начало файла добавить специальный комментарий, подходящий под регэксп «coding[:=]\s*([-\w.]+)», как правило — одного из следующих видов: # coding=<кодировка> # -*- coding: <кодировка> -*- # vim: set fileencoding=<кодировка> : Где <кодировка> — собственно, кодировка, например, «utf-8» или «cp1251». Подробно это описано в PEP 263.

Ответ 2



По опыту - в таких ситуациях обычно виновата кодировка БД…

воскресенье, 15 марта 2020 г.

C#. Как программе подключиться к БД access, если у пользователя microsoft access не установлен?

#c_sharp #база_данных #access


База данных в access, .mdb (97-2003г)
При подключении к базе данных использую следующую конструкцию

public OleDbConnection con1 = new OleDbConnection();
public OleDbCommand cmd1 = new OleDbCommand();
public void loadDb()
    {   
        con1.ConnectionString = Data.connectionString;
        cmd1.Connection = con1;
    }


где

Data.connectionString = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=|DataDirectory|\\db.mdb";


Проверяю, есть ли подключение таким способом:

    public bool checkCon(OleDbConnection con)
    {
        try
        {
            con.Open();
            con.Close();
            return true;
        }
        catch
        {
            return false;
        }
    }


На моем пк подключение работает исправно. У преподавателя пишет, что не может цепануться
к бд. (Но у него Access есть на компьютере, однако отсутствует visual)
У знакомых некоторых цепляется (у них тоже установлен acess, visual studio)
У других подключение не создается. (нет access"a, нет visual studio)

Собственно, как быть?
Быть может ConnectionString изменить? Использовать более старые драйвера или как.
    


Ответы

Ответ 1



Вроде как сам разрешил проблему, корявенько конечно, ну как умею %) Для начала воспользовался информацией про connectionString https://www.connectionstrings.com/access/ Затем, Data.connectionString у меня формируется таким способом: StreamReader s = File.OpenText(Application.StartupPath + "\\path.txt"); Data.connectionString = s.ReadLine(); s.Close(); Data.connectionString = Data.connectionString + Application.StartupPath + "\\db.mdb"; Где path.txt содержит одну строку: Provider=Microsoft.Jet.OLEDB.4.0;Data Source=

Ответ 2



Так у Вас в решении ответ на Ваш вопрос. Если Вы в первом случае измените "Provider=Microsoft.ACE.OLEDB.12.0" на "Provider=Microsoft.Jet.OLEDB.4.0" все должно работать. В первом случае вы указываете что у Вас Access 2012 (по-моему, если не ошибаюсь), а во-втором (Jet.OLEDB.4.0) Вы указываете на Access 97-2003. Начиная с Access 2007 там большие изменения произошли.... Я боюсь напутать в версиях, но Microsoft.ACE.OLEDB.12.0 ставится, по-моему, с Net.Framework 4.5..., а Microsoft.Jet.OLEDB.4.0 стоит даже на ХР.

Система тестирования 2. Как правильней спроектировать БД?

#mysql #база_данных


В продолжение этого вопроса.

Имеется примерно такая структура БД:

Таблица Тест хранит в себе номер вопроса и три ответа к нему.

Таблица Answer - правильный ответ к вопросу.

Интересует, собственно, таблица Тест. Она не расширяема, как видите. Чтобы создать
новый тест - нужно создавать новую таблицу, чтобы добавить ещё несколько вариантов
ответа - нужно создавать новые столбцы.

Как сделать правильно? Спасибо.


    


Ответы

Ответ 1



Вот хорошее расширяемое решение: [question] id text qtype [answer] id text isright question_id order [user_answer] id user_id question_id answer_id text Пример данных: [question] id text qtype 1 "Сколько лун на небе?" 1 2 "Столица Франции?" 1 [answer] id text isright question_id order 1 "Одна" 1 1 1 2 "Две" 0 1 2 3 "Три" 0 1 3 4 "Париж" 1 2 1 5 "Лондон" 0 2 2 6 "Нью-Йорк" 0 2 3 [user_answer] id user_id question_id answer_id text 1 1 1 1 "" 2 1 2 2 ""

Ответ 2



QUESTION: idQ | TypeQ | TextQ TEST: id | idQ | Answer - привязываете сколько угодно ответов к вопросу ANSWER: id | idQ | TrueAnswer - правильные ответы привязываете к id вопроса

Обновление ListView после удаления item

#java #android #база_данных #listview #android_fragment


Здравствуйте. Никак не получается обновить ListView.

Он находится во фрагментах.

При добавлении записи все отлично, ListView обновляется.

Но после удаления приходится листать фрагменты влево, вправо, чтобы удаленные записи
пропали.

Надеюсь тут достаточно информации...

помогите пожалуйста!

Программист я так себе... Не ругайте сильно если че...

int currentPosition;
ListView lvSimple;
View view = inflater.inflate(R.layout.fragment, null);
Cursor c;

static PageFragment newInstance(int page) {
        currentPosition = page;
        PageFragment pageFragment = new PageFragment();
        Bundle arguments = new Bundle();
        arguments.putInt(ARGUMENT_PAGE_NUMBER, page);
        pageFragment.setArguments(arguments);
        return pageFragment;
    }

public void populateListView(int i) {
        c = myDB.getMonthRows();
        switch (i){
            case 0:
                c = myDB.getMonthRows();
                Log.d("ME", "0 block");
                break;
            case 1:
                Log.d("ME", "1 block");
                c = myDB.getAllRows();
                break;
            case 2:
                c = myDB.getMonthRows();
                Log.d("ME", "2 block");
                break;
            case 3:
                c = myDB.getMonthRows();
                Log.d("ME", "3 block");
                break;
        }
        String[] fromFieldNames = new String[]{DBAdapter.KEY_DATE, DBAdapter.KEY_AREA,
DBAdapter.KEY_PASSENGER};
        int[] toViewsID = new int[]{R.id.tvItemDate, R.id.tvItemArea, R.id.tvItemPassenger};
        SimpleCursorAdapter myC = new SimpleCursorAdapter(view.getContext(), R.layout.item,
c, fromFieldNames, toViewsID, 0);
        myC.setViewBinder(new SimpleCursorAdapter.ViewBinder() {
            @Override
            public boolean setViewValue(View view, Cursor cursor, int columnIndex) {
                if (columnIndex == 1) {
                    String createDate = cursor.getString(columnIndex);
                    textView = (TextView) view;
                    textView.setText(dateFormat(createDate));
                    return true;
                }
                return false;
            }
        });
        if(c!=null){
            c.requery();
        }
        lvSimple = (ListView)view.findViewById(R.id.lvSimple);
        myC.notifyDataSetChanged();
        lvSimple.setAdapter(myC);
        lvSimple.invalidateViews();
        registerForContextMenu(lvSimple);
    }

@Override
    public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo
menuInfo) {
        super.onCreateContextMenu(menu, v, menuInfo);
        menu.add(0, CM_DELETE_ID, 0, R.string.delete_record);
    }

public boolean onContextItemSelected(MenuItem item) {
        if (item.getItemId() == CM_DELETE_ID) {
            // получаем из пункта контекстного меню данные по пункту списка
            AdapterView.AdapterContextMenuInfo acmi = (AdapterView.AdapterContextMenuInfo)item.getMenuInfo();
            // извлекаем id записи и удаляем соответствующую запись в БД
            myDB.deleteRow(acmi.id);
            myC.notifyDataSetChanged();
            populateListView(currentPosition);
            return true;
        }
        return super.onContextItemSelected(item);
    }

    


Ответы

Ответ 1



Пересоздавать адаптер не нужно. Т.е. вызов populateListView() лишний. notifyDataSetChanged() достаточно для обновления списка. Смысла в вызове invalidateViews() нет. Этот метод предназначен для обновления вьюшек, может быть вызван если меняются сами view (например, при переходе в action mode решите поменять фон или шрифты, отступы и т.д.), а не данные. Остальное правильное поведение при изменении данных осуществляется через notifyDataSetChanged(). В общем много лишнего, но даже решив проблему с обновлением, все равно придется переписывать. А именно, касаемо requery и прочего кода в олдскульном стиле, то правильная работа с курсорами и адаптерами нынче реализуется через Loader'ы (см. статья на StartAndroid'е). В частности комментарий к устаревшему методу requery говорит, что правильно пересоздавать курсор (в другом потоке) и вызывать adapter.changeCursor(newCursor). Выполняя requery (а изначально получив и передав в адаптер курсор) в основном потоке, вы можете получить ANR (скорее всего на новых api оно скоро просто не будет собираться)... Loader'ы помогают с этим делом.

пятница, 13 марта 2020 г.

TSQL, “простой некластеризованный индекс”

#sql #база_данных #sql_server


Есть несколько индексов такого вида:

CREATE INDEX IX_ProductVendor_VendorID ON Purchasing.ProductVendor (VendorID);


На MSDN здесь (в разделе "примеры", первый пример) сказано, что это "простой некластеризованный
индекс". Что это значит? Обычный первичный ключ? Может быть, глупый вопрос, но для
меня не очевидно, хотелось бы быть уверенным.
    


Ответы

Ответ 1



На Хабре есть аааааабалденная статья на тему индексов. Очень советую. Если вкратце, то: Индекс использует дерево для быстрого обращения к данным. У кластеризованного индекса в листьях дерева лежат сами строки данных. В силу природы дерева данные хранятся в уже отсортированном виде, поэтому кластеризованный индекс может быть только один. У некластеризованного индекса в листьях дерева лежат указатели на строки данных, т.е. для чтения данных необходима еще одна операция. Т.о. кластеризованных индексов у таблицы может быть несколько. Что это значит? Обычный первичный ключ? Понятие первичного ключа в общем-то не связано с индексом. В таблице может быть колонка, являющаяся первичным ключом, но без индекса. Однако на первичные ключи как правило создают кластеризованный индекс. В вашем вопросе VendorID это скорее просто foreign key -- на них обычно создают некластеризованные индексы.

Включение простой базы данных в проект для работы через запросы (SqlConnection, SqlCommand)

#c_sharp #sql #база_данных #visual_studio #sql_server


Visual Studio 2016.
Я пока умею работать с базой данных только так: создаю базу данных в (localDb)\Projects,
генерю таблицы из файла со скриптом sql, потом вытаскиваю или записываю данные с помощью
SqlCommand.
А включается ли она в проект, чтобы программа работала на другом компе? У меня что-то
сомнения возникли.


Если не включается, то объясните пожалуйста на пальцах для такого дубины, как я -
возможно ли создать локальную БД внутри проекта, чтобы можно было с ней точно также
работать запросами?
Если тыкнуть "Создать элемент", есть три варианта, "БД, основанная на службах", "Локальная
БД", "Набор данных". Каждый из вариантов предполагает кучу разных настроек, которые
мне по-моему нафиг не сдались. Думал, раз мне нужна локальная база, то вариант "Локальная
БД" - самый логичный. Но не так всё просто.Глянул "Набор данных" - сходу увидел, что
там не запросы, и закрыл. Если выбрать локальную, то там еще 2 варианта - "Набор данных",
"Модель данных EDM". То, что здесь опять есть набор данных - сбивает меня с толку.
Модель данных у меня долго создавалась, но там надо собственно рисовать модель, что
мне не нужно.
Короче, я что-то ни фига не понял, помогите пожалуйста дураку.


    


Ответы

Ответ 1



Создаем проект; Источники данных - Добавить новый источник данных; База данных - Набор данных - Создать подключение, вводим имя файла базы данных. (Использовать аутентификацию Windows). Отмечаем галочкой Да, сохранить подключение как - Готово; Вот у вас есть пустая локальная база данных подключенная к вашему приложению. При компиляции файл вашей бд будет скопирован в папку с вашей программой. В Обозревателе баз данных появляется ваша база данных. Выбираете ее, нажимаете правой кнопкой мыши, в меню выбираете Новый запрос. Там выполняете ваш sql скрипт по созданию структуры базы. Либо сами ручками, открываете подпапку Таблицы, Хранимые процедуры, Представления и т.п. и там создаете все что необходимо. После этого в Источнике данных выбираете: Настроить источник данных с помощью мастера, там будет показана ваша бд. Отмечаете галочками необходимые таблицы, которые вам нужны в программе. После они появляются в виде дерева в источнике данных. Можно взять любую таблицу или отдельный ее столбец и перетянуть на форму. При этом автоматом создастся подключение необходимых компонентов для отображения данных.

воскресенье, 8 марта 2020 г.

Фиксированное значение столбца (= null) в зависимости от значения другого столбца

#база_данных #postgresql


В таблице tablename есть столбцы type и arg. Нужно ввести ограничение, по которому
при type = 1, всегда arg = null.

Каким образом это можно организовать в PostgreSQL? Версия 9.5.2.

Можно реализовать это на уровне приложения, но требуют, именно, на уровне СУБД. Чтобы
она не дала нарушить это правило.
    


Ответы

Ответ 1



ALTER TABLE test ADD CONSTRAINT null_arg CHECK ((type = 1 AND arg IS NULL) OR type <> 1)