Страницы

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

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

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

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



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

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

Сложный запрос UPDATE

#запрос #sql


Необходимо обновить ячейку таблицы в БД ситуация осложняется тем что в таблице к
одному id может быть несколько записей, а нужно лишь к одно из них.
Придумал такую штуку
UPDATE ".pref."iq_history  SET  hod='поле1'  WHERE ind=(SELECT MAX(ind) FROM tests_iq_history
WHERE user_id='id_ пользователя'

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


Ответы

Ответ 1



У вас есть возможность добавить автоинкрементный PRIMARY KEY к вашей таблице tests_iq_history? Если да, то выборка бы упростилась Если нет, то может разбить на 2 запроса? maxId = SELECT MAX(ind) FROM tests_iq_history WHERE user_id='id_ пользователя'; UPDATE ".pref."iq_history SET hod='поле1' WHERE ind=maxId Но, честно говоря, использование MAX на большом объеме данных будет крайне медленно. Вероятно, лучше переписать так: maxId = SELECT ind FROM tests_iq_history WHERE user_id='id_ пользователя' ORDER BY ind DESC LIMIT 1; Но тут надо быть осторожным, т.к. может использоваться файловая сортировка, поэтому надо экспериментировать с PRIMARY KEY/UNIQUE по нескольким полям

Ответ 2



Можно сделать вложенный внутренний подзапрос. UPDATE `".pref."iq_history` SET `hod`='поле1' WHERE `ind`=(SELECT `ind` from (SELECT MAX(`ind`) FROM `tests_iq_history` WHERE `user_id`='?')x); или UPDATE `".pref."iq_history` SET `hod`='поле1' WHERE `ind`=(SELECT `ind` from (SELECT `ind` FROM `tests_iq_history` WHERE `user_id`='?' ORDER BY `ind` DESC LIMIT 1)x); Любопытно, что в разных версиях MySQL запросы выполняются по-разному. Поэтому стоит использовать EXPLAIN и при необходимости добавлять индексы. Для второго запроса, к примеру, (user_id, ind).

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

Как транспонировать результаты sql-запроса

#sql #запрос


Есть таблица T:

id    value
2      a
3      a
4      b
5      c


Необходимо сформировать запрос, который бы вернул следующий набор:

a b c
2 1 1


Если написать такой запрос:

SELECT value, Count(value)
FROM T
Group by value


то получатся результаты:

a 2
b 1
c 1


А вопрос заключается в том как этот результат повернуть, либо как написать правильный
запрос. Ковырялся с UNION и с PIVOT не получилось.
    


Ответы

Ответ 1



Используйте CASE или PIVOT. Здесь, фактически, ваш случай.

Ответ 2



при помощи интернета и какой-то... получилось такое. Это только для MySQL, как я понимаю, из-за group_concat. Но, может, чем поможет drop table if exists t1; create table t1 (id int, value char(1)); insert into t1 values (2, 'a'), (3, 'a'), (4, 'b'), (5, 'c'); select group_concat(if(v='a', c, null)) a, group_concat(if(v='b', c, null)) b, group_concat(if(v='c', c, null)) c from (select value v, Count(value) c from t1 group by value ) temp a b c 2 1 1

Ответ 3



Не претендую на изящность решения, но вот вариант с курсором: DECLARE @T2 table (id int, value char(1)) INSERT INTO @T2 values (2, 'a'), (3, 'a'), (4, 'b'), (5, 'c') DECLARE @vals varchar(10) DECLARE @cnts varchar(10) DECLARE @v char(1) DECLARE @c int DECLARE @cur cursor SET @cur = cursor local for SELECT value, COUNT(value) FROM @T2 GROUP BY value OPEN @cur FETCH NEXT FROM @cur INTO @v, @c WHILE @@FETCH_STATUS = 0 BEGIN IF @vals IS NULL SET @vals = @v ELSE SET @vals = @vals + ' ' + @v IF @cnts IS NULL SET @cnts = CAST(@c as varchar(10)) ELSE SET @cnts = @cnts + ' ' + CAST(@c as varchar(10)) FETCH NEXT FROM @cur INTO @v, @c END CLOSE @cur DEALLOCATE @cur -- ну и собственно результат: SELECT @vals SELECT @cnts

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

MySQL: Как получить последние записи одним запросом?

#mysql #запрос


В таблице в хронологическом порядке фиксируются состояния пользователей (и их изменения),
например,

datetime   | uid | status 
2016-07-01 | 14  | Register
2016-07-01 | 14  | Active
2016-07-02 | 15  | Active
2016-07-02 | 16  | Register
2016-07-02 | 14  | Pending
2016-07-04 | 16  | Pending


Как правильно сформулировать MySQL-запрос, чтобы в итоге получить

datetime   | uid | status  
2016-07-02 | 15  | Active
2016-07-02 | 14  | Pending
2016-07-02 | 16  | Pending


То есть как можно в MySQL-запросе указать, чтобы выводились только самые последние
состояния для уникальных uid?
Пытался GROUP BY, DISTINCT и MAX(), но время выводит точно максимальное, а значение
status – не максимальное.

P.S. Саму таблицу дал схематически, время фиксируется до секунды, пересечений по
времени нет. Нужна просто последняя запись по каждому из uid. Буду благодарен за хотя
бы подсказку, в каком направлении смотреть.
    


Ответы

Ответ 1



select uid, datetime, status from tablename join ( select uid, max(`datetime`) as datetime from tablename group by uid ) lastvalues using(uid, datetime) При условии уникальности (а лучше - уникального индекса) пары uid & datetime будет возвращать корректный результат.

Ответ 2



SELECT uid, max(`datetime`) as datetime, substr(max(concat(`datetime`,status)),20) as status FROM tablename GROUP BY uid Смещение 20 в substr указано исходя из предположения, что поле datetime имеет тип данных datetime. Для других типов данных надо указать подходящее смещение исходя из длины поля даты в символьном представлении. Так же убедитесь, что при ваших региональных настройках при автоматическом преобразовании даты к строке компоненты идут в порядке год-месяц-день, для правильной сортировки.

Ответ 3



Кажется, так: SELECT max(`datetime`) as datetime, uid, status FROM tablename GROUP BY uid Не могу гарантировать, что это работает, как задумывалось (на тестовой выборке дало ок-результат), нужно стороннее подтверждение/опровержение

Как правильно объединить два столбца и сделать по нему JOIN

#mysql #sql #запрос


Всем привет!
У меня есть две таблицы:
Мои друзья(friends): id, user1_id, user2_id, joined
Пользователи(users): id, name, sename

Хочу достать значение из поля user1_id и user2_id объединить их в один столбец, и
уже по этому столбцу сделать INNER JOIN с таблицей users.

С объединением проблем не возникло, делаю так:

SELECT user1_id as friend_id, joined
FROM friends
WHERE user2_id = 7 #Выбираем всех друзей пользователя из второй колонки
UNION
SELECT user2_id, joined
FROM friends
WHERE user1_id = 7 #Выбираем всех друзей пользователя из первой колонки


А вот JOIN никак не могу подружить с union. Делаю так:

SELECT users.*, friends.user1_id as friend_id, friends.joined
FROM users
INNER JOIN friends
ON friends.friend_id = users.id
WHERE friends.user2_id = 7
UNION
SELECT user2_id, joined
FROM friends
WHERE user1_id = 7


В двух словах:
Друзья пользователя могут находится в колонке friends.user1_id или friends.user2_id,
чтобы упростить запрос я хочу объединить эти две колонки и уже по этой колонке достать
нужных пользователей из таблице users.
    


Ответы

Ответ 1



SELECT users.*, friend_id, joined FROM( SELECT user1_id as friend_id, joined FROM friends WHERE user2_id = 7 #Выбираем всех друзей пользователя из второй колонки UNION SELECT user2_id, joined FROM friends WHERE user1_id = 7 #Выбираем всех друзей пользователя из первой колонки )friends INNER JOIN users ON friends.friend_id = users.id

среда, 4 марта 2020 г.

Как быстро получить пропущенное в поле значение?

#mysql #sql #запрос




Есть таблица sample. Важный уникальный индекс UNIQUE( laboratory_prefix_id, sample_number
). Последний задаёт группу, в пределах которой не может быть повторяющихся sample_number.
Вопрос следующий - как быстро получить список пропущенных sample_number в пределах
запрошенной группы laboratory_prefix_id? И если не список, то хотя бы 1 наименьшее
значение.

Например, если искать в группе laboratory_prefix_id=5, то максимальный sample_number=15,
но перед ним пропущены значения 11, 12, 13, 14 - их (или хотя бы значение 11) хотелось
бы как-то получить (т.е. получить просто sample number пропущенных значений). Как это
быстро сделать?



Дамп таблицы для примера прикладываю

CREATE TABLE `sample` ( 
    `id` Int( 10 ) UNSIGNED AUTO_INCREMENT NOT NULL,
    `person_id` Int( 10 ) UNSIGNED NOT NULL,
    `laboratory_prefix_id` TinyInt( 3 ) UNSIGNED NOT NULL DEFAULT '1',
    `sample_number` Smallint( 5 ) UNSIGNED NOT NULL,
    `total_cost` Decimal( 6, 2 ) NOT NULL DEFAULT '0.00',
    `completion_date` Date NULL,
    `barcode` VarChar( 15 ) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL,
    `country_id` TinyInt( 3 ) UNSIGNED NOT NULL DEFAULT '20',
    `sample_priority` TinyInt( 1 ) UNSIGNED NOT NULL DEFAULT '1',
    `sample_note` VarChar( 255 ) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL,
    `registration_date` Date NOT NULL,
    PRIMARY KEY ( `id` ),
    CONSTRAINT `UK_sample` UNIQUE( `laboratory_prefix_id`, `sample_number` ) )
CHARACTER SET = utf8mb4
COLLATE = utf8mb4_general_ci
COMMENT 'Образцы'
ENGINE = InnoDB
AUTO_INCREMENT = 57;

INSERT INTO `sample`(`id`,`person_id`,`laboratory_prefix_id`,`sample_number`,`total_cost`,`registration_date`,`completion_date`,`barcode`,`country_id`,`sample_priority`,`sample_note`)
VALUES 
( '15', '120', '8', '155', '0.00', '2017-08-18', NULL, '12-55fff', '20', '3', 'sdfsdfsdf' ),
( '22', '120', '7', '1', '0.00', '2017-08-11', NULL, NULL, '20', '1', NULL ),
( '32', '120', '7', '10', '0.00', '2017-08-19', NULL, NULL, '20', '1', NULL ),
( '33', '165', '5', '1', '0.00', '2017-08-19', NULL, NULL, '20', '2', NULL ),
( '34', '165', '5', '2', '0.00', '2017-08-19', NULL, NULL, '20', '2', NULL ),
( '35', '166', '5', '3', '0.00', '2017-08-19', NULL, NULL, '20', '3', NULL ),
( '36', '166', '5', '4', '0.00', '2017-08-19', NULL, NULL, '20', '3', NULL ),
( '37', '167', '5', '5', '0.00', '2017-08-19', NULL, NULL, '20', '2', '6лоло' ),
( '38', '168', '5', '6', '0.00', '2017-08-19', NULL, NULL, '20', '1', NULL ),
( '39', '168', '5', '7', '0.00', '2017-08-19', NULL, NULL, '20', '1', NULL ),
( '40', '168', '5', '8', '0.00', '2017-08-19', NULL, NULL, '20', '1', NULL ),
( '41', '168', '5', '9', '0.00', '2017-08-19', NULL, NULL, '20', '1', NULL ),
( '42', '168', '5', '10', '0.00', '2017-08-19', NULL, NULL, '20', '1', NULL ),
( '43', '173', '7', '2', '0.00', '2017-08-20', NULL, 'к', '17', '2', 'ккк' ),
( '44', '173', '5', '15', '0.00', '2017-08-18', NULL, 'ne', '20', '2', '=' ),
( '47', '180', '8', '5', '0.00', '2017-08-20', NULL, NULL, '20', '2', NULL ),
( '49', '120', '8', '161', '0.00', '2017-08-18', NULL, '12-55fff', '20', '2', 'sdfsdfsdf' ),
( '54', '120', '6', '212', '0.00', '2017-09-01', NULL, NULL, '20', '2', NULL ),
( '55', '120', '6', '213', '0.00', '2017-09-01', NULL, NULL, '20', '3', NULL ),
( '56', '120', '6', '214', '0.00', '2017-09-01', NULL, NULL, '20', '2', NULL );

    


Ответы

Ответ 1



SELECT @count FROM sample, (select @count := 0) dummy WHERE sample.laboratory_prefix_id = 5 AND (@count := @count+1) < sample.sample_number ORDER BY sample.sample_number ASC LIMIT 1; Не работает в случае, если для заданного sample.laboratory_prefix_id нет ни одной записи. Если начальное значение не равно 1, следует откорректировать как псевдотаблицу dummy, так и условие во WHERE. Вот более универсальный запрос (соответствует условию типа "найти первый свободный в группе laboratory_prefix_id = 5, но не менее sample.sample_number = 4"): SET @laboratory_prefix_id = 5; SET @min_sample_number = 4; SELECT @count FROM sample, (select @count := @min_sample_number-1) dummy WHERE sample.laboratory_prefix_id = @laboratory_prefix_id AND sample.sample_number > @min_sample_number-1 AND (@count := @count+1) < sample.sample_number ORDER BY sample.sample_number ASC LIMIT 1; Недостаток - тот же. Ну и запрос, избавленный от этого недостатка: SET @laboratory_prefix_id = 5; SET @min_sample_number = 4; ( SELECT @count FROM sample, (select @count := @min_sample_number-1) dummy WHERE sample.laboratory_prefix_id = @laboratory_prefix_id AND sample.sample_number > @min_sample_number-1 AND (@count := @count+1) < sample.sample_number ORDER BY sample.sample_number ASC LIMIT 1 ) UNION ALL ( SELECT @min_sample_number ) ORDER BY 1 DESC LIMIT 1;

Ответ 2



select s1.sample_number+1 from sample s1 left join sample s2 on s2.sample_number = s1.sample_number+1 AND s2.laboratory_prefix_id=5 where s1.laboratory_prefix_id=5 and s2.id is null order by s1.sample_number limit 1;

среда, 12 февраля 2020 г.

SQL-запрос для массового заполнения таблицы

#sql #запрос


Приветствую, мне надо прописать одну картинку для товаров с id от 1 до 1261

Команда

INSERT INTO `catalogue_productimage` (`id`, `original`, `caption`, `display_order`,
`date_created`, `product_id`)
VALUES (1, 'images/products/2016/09/none.png', '', 0, '2016-09-29 11:07:36', 1);


делает нужное для товара с id 1. Не в ручную же 1261 такой запрос создавать, подскажите,
как автоматизировать.
    


Ответы

Ответ 1



Предполагаю, что у вас есть некая таблица продуктов в которой уже существуют записи с такими id и вы хотите в связанную с ней таблицу изображений вставить указанные строки. Если так, то вы можете написать что то вроде: INSERT INTO `catalogue_productimage` (`id`, `original`, `caption`, `display_order`, `date_created`, `product_id`) select id, 'images/products/2016/09/none.png', '', 0, '2016-09-29 11:07:36', id from products where id between 1 and 1261 Если такой таблицы нет, то можно воспользоваться самой же таблицей catalogue_productimage. Для этого вставляем в нее вашу первую запись, а последующие вставляем несколькими запросами вроде таких (если в таблице изначально только 1 запись): INSERT INTO `catalogue_productimage` (`id`, `original`, `caption`, `display_order`, `date_created`, `product_id`) select id+1, original, caption, display_order, date_created, id+1 from catalogue_productimage; INSERT INTO `catalogue_productimage` (`id`, `original`, `caption`, `display_order`, `date_created`, `product_id`) select id+2, original, caption, display_order, date_created, id+2 from catalogue_productimage; INSERT INTO `catalogue_productimage` (`id`, `original`, `caption`, `display_order`, `date_created`, `product_id`) select id+4, original, caption, display_order, date_created, id+4 from catalogue_productimage; Фокус в том, что каждый последующий запрос создает в 2 раза больше записей, чем предыдущий, таким образом что бы дойти до значений около 1261 нам понадобится не более 11 таких запросов. Запросы отличаются друг от друга только прибавлением к ID очередной степени двойки. В последнем запросе нам надо будет ограничить максимальный id, запрос тогда получит условие where id<=1261-1024.

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

SQL. Подзапросы. В чем ошибка (вывод всех продавцов, которые продали больше чем продавец N)?

#sql #база_данных #oracle #запрос #запрос_в_запросе


Есть  таблица SALES c полями:


ID_SALE - ID продажи
name_good - название товара
date_sale - дата продажи
FIO_saler -ФИО продавца
price- цена товара


Нужно вывести всех продавцов, которые продали больше чем продавец “Иванов Иван” (записи
с таким продавцом должны быть) за май 2015.

Вопрос: почему возникает ошибка, как её исправить, чтобы выводилась нужная информация?

 select FIO_saler,price
  from sales
 where sum(price)> all
    (SELECT price
     from sales
     where FIO_saler='Иванов Иван Иванович' 
    );
    /

    


Ответы

Ответ 1



SELECT FIO_saler, SUM(price) AS summa FROM sales WHERE date_sale > '2015-12-23' AND date_sale < '2015-12-31' GROUP BY FIO_saler HAVING SUM(price) > (SELECT SUM(price) FROM sales WHERE FIO_saler='Иванов Иван Иванович'); Проверка

Ответ 2



SELECT FIO_saler, price FROM SALES WHERE FIO_saler IN (SELECT FIO_saler FROM SALES GROUP BY FIO_saler HAVING SUM(PRICE) > (SELECT SUM(price) FROM SALES WHERE FIO_saler = 'Иванов Иван Иванович') ) AND date_sale BETWEEN _Начало_ AND _Конец_ Вам остается только наложить условие на период продажи вместо _Начало_ и _Конец_ в соответствии с типом данных поля.

суббота, 1 февраля 2020 г.

Эффективный способ выбрать максимум

#sql #oracle #запрос #oracle12c


Как можно наиболее эффективно выбрать максимальное значение. Пока созрело 3 варианта:

1 - Классика

select max(log_id) from log where param = 16


2 - Извращения

select log_id from log where param = 16 order by log_id desc nulls last fetch next
1 rows only


3 - Аналитика

select v from
(
    select max(log_id) over () v from log where param = 16 
)
where rownum = 1


Судя по планам запросов в моей среде БД самый эффективный - последний. Может есть
варианты еще более эффективные?
    


Ответы

Ответ 1



А вы уверены, что это является узким местом в вашей БД? Или вы пытаетесь выполнить преждевременную оптимизацию до появления самой проблемы? Преждевременная оптимизация-корень всех бед Имхо, первый вариант с учетом того, что существует индекс по param должен отрабатывать моментально. На сколько я знаю, то индекс по полю по которому считается MAX тоже должен ускорить выборку, так как данные будут заранее отсортированы. +БД должна кешировать данные=> повторное выполнение запроса с другими параметрами должно отработать еще быстрее за счет того, что все данные были ранее вычитаны и загружены в ОЗУ. Если разница между этими 3 решениями и есть, то это какие-то считанные мс, которые не стоят уродства кода.

Ответ 2



Если у вас может быть более одной записи с param = 16, то 3-й вариант может вернуть неправильный результат, потому что предикат rownum = 1 отработает до max(log_id). Поэтому я бы выбрал 1-й вариант.

пятница, 31 января 2020 г.

Защита от подделывания данных в ajax запросе самим пользователем

#запрос #ajax #клиент #защита #javascript


Всем привет, уже весь инет перерыл. Представим себе такую ситуацию. У нас есть игра
на js, в которой пользователь набирает очки. Эти очки нужно сохранить на сервер для
создания таблицы рекордов. Рекорд вместе с id пользователя и токеном через ajax передается
на php сервер. Если токен защищает аккаунт пользователя от стороннего вмешательства,
то как защитить рекорд от замены его самим пользователем? Ведь юзеру ничего не мешает
подменить запрос, взяв свой токен, и легко попасть на первое место. Переменная, хранящая
текущий результат на клиенте, зашита в функцию-обработчик. Поэтому пользователь ее
просто так не изменит. А вот запрос подделает запросто. Какие средства защиты нужно
использовать? Помогите!    


Ответы

Ответ 1



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

Ответ 2



Цитата с хабра: Написал метод который дублировал результат. В одном параметре передавался реальный, в другом шифрованный результат, методом замены символа по ключу. А далее, на сервере оба сравниваются и если что-то не соответствует, то – бан по аккаунту. И еще, сервер отправляет сгенрированный ключ при первом обращении. Клиент же, должен его вернуть с результатом. Без этого ключа, результат не примется и если все соответствует, и все проходит проверку, то результат записывается в БД, и генерируется новый ключ, который опять отдается клиенту. Это сделано для того, чтобы повторно запрос с результатом не могли отправить, как делается в программе «Charles».

пятница, 24 января 2020 г.

Вызов метода messages.removeChatUser - VK Android SDK

#android #android_sdk #vkontakte_api #вконтакте #запрос


В VK API существует такой метод как messages.removeChatUser, позволяющий как исключить
пользователя из беседы, так и покинуть беседу самому. Не могу разобраться, как сделать
запрос к этому методу.
Я начинаю запрос таким образом:

VKRequest request = VKApi.messages().


но после точки есть лишь часть методов и нет removeChatUser. На скриншотах видно,
что в wall их достаточно много, а в messages многие методы отсутствуют. Или я что-то
делаю не так?




Я также пытался сделать запрос к методу следующим образом:

VKRequest request = new VKRequest("messages.removeChatUser", VKParameters.from("chat_id",
2, "user_id", мой id));


Но, кажется, такой способ тоже не прошёл.
Помогите сделать запрос к vk.com/dev/messages/removeChatUser.
    


Ответы

Ответ 1



Может быть "капитаню", но первым делом нужно проверить есть ли доступ "Для вызова этого метода Ваше приложение должно иметь права: messages". Часть методов не реализованы в VK SDK Andoid, поэтому для их вызова необходимо делать запросы. Запрос у вас написан правильно. Пришлите код ошибки, который вам приходит

firebase запрос на проверку нескольких полей

#android #запрос #firebase


Никак не приходит прозрение касательно того как сделать правильный запрос.
Структура(схематически):

root
{
    autocreatedkey
   {
        user_id1 : true
        user_id2 : true
        mess
        {
            ...
        }
   }
} 


Необходимо написать такой запрос, который бы из множества записей нашел ту где "user_id1"
и "user_id2", такие какие были запрошены(в запросе) и вернул узел "autocreatedkey".
 И нет таких двух узлов у которых бы значения "user_id1" и "user_id2" одновременно
совпадали. "autocreatedkey" - создан автоматически

Все мои попытки приводят либо к тому что я получаю в итоге узел "root" из-за того
что не знаю значения "autocreatedkey", либо что генерится не существующий ключ или
вообще к ошибкам.

Спасибо! 

---UPDATE---

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

Вот код(отрывок) как я решил вопрос:

DatabaseReference mDatabase;
DatabaseReference dRef;
Boolean RoomCreated = false;
//...
 mDatabase.child("root").addListenerForSingleValueEvent(
                new ValueEventListener() {
                    @Override
                    public void onDataChange(DataSnapshot dataSnapshot) {
                        Iterable iter =  dataSnapshot.getChildren();
                        for (DataSnapshot it : iter)
                        {
                          if(it.hasChild(mUser.getUid()) && //<---"user_id1"
                                  it.hasChild(FUid ))  //<---"user_id2"
                            {
                                dRef = it.getRef();
                                RoomCreated = true;
                                break;
                            }
                        }
                    }

                    @Override
                    public void onCancelled(DatabaseError databaseError) {
                    }
                });

    


Ответы

Ответ 1



Обходите ветку со значениями и записываете их в коллецию. А уж из коллеции легко вытащить любое значение. mDatabase.getSomeReference().addListenerForSingleValueEvent(new ValueEventListener() { @Override public void onDataChange(DataSnapshot dataSnapshot) { mylisty.clear(); Map newPost = (Map) dataSnapshot.getValue(); for (Map.Entry entry : newPost.entrySet()) { mainID = entry.getKey(); Map newPost4 = (Map) entry.getValue(); for (Map.Entry entry2 : newPost4.entrySet()) { Map properties = (Map) entry.getValue(); strName = properties.get("lowerID1").toString(); strCity = properties.get("lowerID2").toString(); } mylisty.add(new InfoClass(strName,strCity)); } } @Override public void onCancelled(DatabaseError databaseError) { } });

Не добавляется сss свойство через jquery

#javascript #css #веб_программирование #запрос


Не могу понять почему не меняется свойство у ссылки, при нажатии, при этом класс
добавляется 

Вот сам код

$(function() {
    $(".item-list-dir").click(function () {
        $(".item-list-dir").removeClass("active");
        $(this).addClass("active");

        $(this).hasClass("kitchen").css("background-color", "yellow");
    });
});

    


Ответы

Ответ 1



https://api.jquery.com/hasclass/ if ($(this).hasClass("kitchen")) $(this).css("background-color", "yellow");

Ответ 2



Сделайте так: if ($(this).hasClass("kitchen")){ $(this).css({backgroundColor: "yellow"}); } Документация для функции .css().

Ответ 3



Заменил hasClass на filter. $(function() { $(".item-list-dir").click(function () { $(".item-list-dir").removeClass("active"); $(this).addClass("active"); //$(this).hasClass("kitchen").css("background-color", "yellow"); $(this).filter(".kitchen").css("background-color", "yellow"); }); }); Нажми меня

суббота, 11 января 2020 г.

Запрос к множественным элементам в XML в MSSQL

#sql #sql_server #xml #запрос


Имеется конструкция вида:


    ...
    ...
    
        
            1
            ...
            ...
            ...
            
                
                    ...
                    ...
                    ...
                
                
                    ...
                    ...
                    ...
                
                
                    ...
                    ...
                    ...
                
            
        
        
            2
            ...
            ...
            ...
            
                
                    ...
                    ...
                    ...
                
                
                    ...
                    ...
                    ...
                
                
                    ...
                    ...
                    ...
                
            
        
    



Количество вложенных lot, как и количество вложенных requirement, не известно.
Я понимаю, как получить элементы в purchseDoc:

SELECT column.value('(purchaseDoc/id) [1]', 'integer') AS 'id' FROM table


Понимаю, как разможить элемент lot с привязкой к purchaseDoc:

SELECT 
t.column.value('(purchaseDoc/id)[1]', 'integer') AS Id,
nodes.setting.value('lotNumber[1]', 'varchar(100)'),
nodes.setting.value('lotObjectInfo[1]', 'varchar(100)')
FROM table t
    CROSS APPLY t.column.nodes('purchaseDoc/lots/lot/.[1]') nodes(setting)


Получаю после данного запроса таблицу вида:

id | lotNumber | lotObjectInfo


Но не понимаю, как мне сделать так, чтобы еще дальше углубиться, чтобы разбить requirement
с привязкой как к lot, так и purchaseDoc, то есть чтобы я получил таблицу вида:

id | purchaseNumber | lotNumber | code | name | content

    


Ответы

Ответ 1



CROSS APPLY делаем по самым вложенным элементам. lotNumber получаем через путь к предкам. SELECT #t.col.value('(purchaseDoc/id)[1]', 'integer') AS Id, #t.col.value('(purchaseDoc/purchaseNumber)[1]', 'integer') AS purchaseNumber, nodes.setting.value('../../lotNumber[1]', 'varchar(100)') AS lotNumber, nodes.setting.value('code[1]', 'varchar(100)') AS code, nodes.setting.value('name[1]', 'varchar(100)') AS [name], nodes.setting.value('content[1]', 'varchar(100)') AS content FROM #t CROSS APPLY #t.col.nodes('purchaseDoc/lots/lot/requirements/requirement/.[1]') nodes(setting)

Ответ 2



Запрос для получения данных из переменной declare @XML xml SELECT @XML = ' 1 100 1 lotObjectInfo_1 customerRequirements_1 purchaseObjects_1 111 name111 content111 112 name112 content112 113 name113 content113 2 lotObjectInfo_2 customerRequirements_2 purchaseObjects_2 211 name211 content211 212 name212 content212 213 name213 content213 9 900 91 lotObjectInfo_91 customerRequirements_91 purchaseObjects_91 9111 name9111 content9111 9112 name9112 content912 9113 name9113 content9113 92 lotObjectInfo_92 customerRequirements_92 purchaseObjects_92 9211 name9211 content9211 9212 name9212 content9212 9213 name9213 content9213 ' SELECT y.requirement.value('(../../../.././id)[1]', 'int') as id, y.requirement.value('(../.././lotNumber)[1]', 'int') as lotNumber, y.requirement.value('(code)[1]', 'INT') AS code, y.requirement.value('(name)[1]', 'varchar(100)') AS name, y.requirement.value('(content)[1]', 'varchar(100)') AS content FROM @xml.nodes('.') as g(r) CROSS APPLY @xml.nodes('/purchaseDoc/lots/lot/requirements/requirement') y(requirement) GO id | lotNumber | code | name | content :- | --------: | ---: | :------- | :---------- 1 | 1 | 111 | name111 | content111 1 | 1 | 112 | name112 | content112 1 | 1 | 113 | name113 | content113 1 | 2 | 211 | name211 | content211 1 | 2 | 212 | name212 | content212 1 | 2 | 213 | name213 | content213 9 | 91 | 9111 | name9111 | content9111 9 | 91 | 9112 | name9112 | content912 9 | 91 | 9113 | name9113 | content9113 9 | 92 | 9211 | name9211 | content9211 9 | 92 | 9212 | name9212 | content9212 9 | 92 | 9213 | name9213 | content9213

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

Запрос к XML в mssql

#sql #sql_server #xml #запрос


Имеется кострукция вида:


   ...
   ...
   
      ...
      ...
      ...
   



Кол-во элементов setting не известно. То есть в каждой записи может присутствовать
от 0 до n данных элементов.

Я понимаю, как вывести единичные элменты. Например, id:

SELECT column.value('(first/id) [1]', 'integer') AS 'id' FROM table


Но вот с множественными элементами возникает вопрос.
Требуется чтобы при запросе я получил список вида:

id | setting
id | setting
....

    


Ответы

Ответ 1



DECLARE @Test XML SET @Test = CAST( ' 100 MyObject p1 p2 2 3 ' AS XML) SELECT t.f.value('(first/id)[1]', 'integer') AS Id, n.s.value('.[1]', 'varchar(100)') AS params, n.s.value('(./param1)[1]', 'varchar(100)') AS param1, n.s.value('(./param2)[1]', 'varchar(100)') AS param2 FROM (SELECT @Test AS f) t CROSS APPLY f.nodes('first/settings/setting/.[1]') n(s) UPD: Для приведенного примера выбор из таблицы: SELECT t.column.value('(first/id)[1]', 'integer') AS Id, nodes.setting.value('.[1]', 'varchar(100)') FROM table t CROSS APPLY t.column.nodes('first/settings/setting/.[1]') nodes(setting)

суббота, 4 января 2020 г.

Как оптимизировать запрос

#mysql #запрос #index


Добрый день, есть вот такая таблица:

CREATE TABLE IF NOT EXISTS `ip_city` (
  `ip_from` int(10) unsigned NOT NULL,
  `ip_to` int(10) unsigned NOT NULL,
  `locid` int(10) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;


Индексы:

ip_from BTREE   ip_from
ip_to   BTREE   ip_to
ip_from_2   BTREE   ip_from, ip_to


И запрос:

SELECT * FROM `ip_city` WHERE (`ip_from` < 2995257412) AND (`ip_to` > 2995257412)


Никак не могу добиться вменяемого результата, никакой индекс не цепляет.
    


Ответы

Ответ 1



Выборки из одной таблицы Возьмем таблицу пользователей с набором личной информации, проиндексированную по адресу электронной почты. Вот пара простых условий, которые могут получить преимущества от индексов: EmailAddress = 'vasya.pupkin@mail.ru' написал равно вместо LIKE так как сам удивился результатам EXPLAIN'а, нужны дополнительные исследования - точно определенное значение всегда имеет возможность использовать индекс, сервер пройдется по дереву и получит точное указание на запись или несколько записей в таблице. Сразу нужно отметить, что, определяя колонку уникальной, автоматически создается индекс по ней. Зачем? Иначе было бы накладно перед каждой вставкой или изменением в таблице проверять все значения поля на соответствие условию уникальности, а так можно быстро проверить существование записи. EmailAddress LIKE 'vacya.pupkin@%' - частичное использование индекса. Повторю, что должна быть определена крайняя левая часть и только она может быть использована для поиска по индексам. Например, для условия EmailAddress LIKE 'vasya.%@mail.ru' тоже будет использован индекс, но в поиске в структуре индекса будет участвовать только vasya., а остальная часть будет проверена последовательным сканированием строк, найденных с помощью индекса. К этому примеру мы вернемся при рассмотрении особенностей составных индексов. Те же условия распространяются на операции с числами: равенство, больше, меньше и другие. Нетрудно догадаться, что некоторые условия можно привести к альтернативным выражениям с использованием элементарных операций, например, BETWEEN, который тоже оптимизируется. (ссылка на источник) В таком случае вы можете попробовать использовать директиву USE INDEX или FORCE INDEX. UPD В качестве оптимизации также можете попробовать в запросе вместо выборки всех полей, "*", перечислить только те поля, которые вам действительно нужны. Это сократит количество выбираемых и пересылаемых данных.

Ответ 2



Оптимизатор начинает использовать индексы только если по его предварительной оценке, количество записей в результате будет не более 30% от общего количества записей в таблице. Иначе, он абсолютно справедливо считает, что быстрее будет тупо перелопатить все записи таблицы не используя индексы. Индекс не будет использован, если использование индекса требует от MySQL прохода более чем по 30% строк в данной таблице (в таких случаях просмотр таблицы, по всей видимости, окажется намного быстрее, так как потребуется выполнить меньше операций поиска). Поэтому ставьте хоть FORCE INDEX или USE INDEX - быстрее не станет.

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

Как в java сделать comit в sql если я хочу закомитить много объектов?

#java #sql #запрос #jdbc


Делаю так:

PreparedStatement ps = conn.prepareStatement(
        "INSERT INTO mydbcall1.Call0 (date,direction,operator,abonentTel,duration,coast1,coast2,corpPhone)" +
                " VALUES(?, ?, ?, ?, ?, ?, ?, ?)");
try {

    ps.setDate(1,  new java.sql.Date(call.date.getTime()) );
    ps.setString(2, call.direction);
    ps.setString(3, call.operator);
    ps.setString(4, call.abonentTel);
    ps.setInt(5, call.duration);
    ps.setDouble(6, call.coast1);
    ps.setDouble(7, call.coast2);
    ps.setString(8, call.corpPhone);
    ps.executeUpdate(); // for INSERT, UPDATE & DELETE

} finally {
    ps.close();
}


метод для 3000 объектов работает больше 1.5 минут.
    


Ответы

Ответ 1



Не создавайте PreparedStatement каждый раз заново. Преимущество PreparedStatement перед обычным Statement именно в том, что можно его заранее отправить на сервер БД для компиляции и переиспользовать повторно. Отправляйте вставки пакетами (batch). Вероятно, вам придется подобрать оптимальный размер пакета. Используйте явное управление транзакцией. По-умолчанию транзакция завершается на каждый запрос к БД (autoCommit = true). Вот пример с применением этих трех рекомендаций (используется try-with-resources): private static final String INSERT_STATEMENT = "INSERT INTO mydbcall1.Call0(date,direction,operator,abonentTel,duration,coast1,coast2,corpPhone) VALUES(?, ?, ?, ?, ?, ?, ?, ?)"; // .... try ( Connection connection = database.getConnection(); PreparedStatement ps = connection.prepareStatement(INSERT_STATEMENT); ) { int i = 0; connection.setAutoCommit(false) for (Call call : calls) { ps.setDate(1, new java.sql.Date(call.date.getTime()) ); ps.setString(2, call.direction); ps.setString(3, call.operator); ps.setString(4, call.abonentTel); ps.setInt(5, call.duration); ps.setDouble(6, call.coast1); ps.setDouble(7, call.coast2); ps.setString(8, call.corpPhone); // ... ps.addBatch(); i++; if (i % 1000 == 0 || i == calls.size()) { ps.executeBatch(); // ограничиваем размер одного пакета тысячей вставок } } connection.commit(); } catch(SQLException e) { connection.rollback(); }

суббота, 21 декабря 2019 г.

Определение свойства, по которому нужно произвести фильтр

#c_sharp #запрос #рефлексия


Здравствуйте. Возник очень тяжелый вопрос с которым я никогда не сталкивался. мне
нужно создать метод, который поймет по какому свойству нужно сделать фильтр. Т.е.,
допустим у меня есть класс 

public class User {
    public string Name {get; set;}
    public string Nick {get; set;}
}


И мне нужно вытащить из базы некоторых пользователей но критерий заранее не известен,
в запросе Name или Nick могут быть null. 

В данный момент это выглядит примерно так: 

//это часть когда находится в классе user
IQarable query ... тут создается query и передается в метод ниже
...

if (!string.IsNullOrEmpty(Name))
        {
                query = query.Where(x => x.VenueName.Contains(Venue));
        }

if (!string.IsNullOrEmpty(Nick))
        {
                query = query.Where(x => x.City.Contains(City));

        } //и так далее 


Внутри блоков If есть еще кое какая проверка, вот поэтому я пытаюсь это вынести в
1 метод, но не в этом суть.

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

if (!string.IsNullOrEmpty(Name))
        {
                query = SearchMethod(query, "Name", "Jhon");
        }


Я не могу представить как мне заменить выражение Where(x => x./*тут свойство, которое
каким-то образом определено*/.Contais("SearchingValue")) что-то другое, что может вычислить
свойство по которому я веду поиск, и подставить его в это выражение. По рефлексии я
смог получить только само свойство.

Type t = this.GetType();
PropertyInfo prop = t.GetProperty("EventName");


Прошу вашей помощи в решении этой проблемы.
    


Ответы

Ответ 1



Отфильтровать IQueryable по Func нельзя. (У вас получится IEnumerable.) Для сохранения IQueryable вам придётся строить Expression (и кажется, вручную). Вот документация. Для вашего случая, если нужно сравнивать значение с константой, можно сделать так (не тестировал, возможны вылеты в рантайме): IQueryable Filter(IQueryable original, Expression> еxtractor, V value) { return original.Where(ProjectionEquals(еxtractor, value)); } Expression> ProjectionEquals(Expression> еxtractor, V value) { var body = Expression.Equal(еxtractor.Body, Expression.Constant(value)); return Expression.Lambda>(body, еxtractor.Parameters[0]); } Пользоваться так: query = Filter(query, x => x.Name, "Jhon"); Внутри Filter можно накрутить, понятно, более сложную логику. Если всё же очень хочется потерять проверки на этапе компиляции и передавать имена свойств как строки, можно так: IQueryable Filter(IQueryable original, string propName, V value) { return original.Where(PropertyEquals(propName, value)); } Expression> PropertyEquals(string propName, V value) { var parameter = Expression.Parameter(typeof(T), "t"); var left = Expression.PropertyOrField(parameter, propName); var body = Expression.Equal(left, Expression.Constant(value)); return Expression.Lambda>(body, parameter); } и пользоваться так: query = Filter(query, "Name", "Jhon"); Понятна схема? Для примера, если вам нужно Contains: Expression> GetContains(string propName, string value) { var parameter = Expression.Parameter(typeof(T), "t"); var prop = Expression.Property(parameter, propName); var containsMethod = typeof(string).GetMethod("Contains", new[] { typeof(string) }); var valueAsExpr = Expression.Constant(value, typeof(string)); var contains = Expression.Call(propOrField, containsMethod, valueAsExpr); return Expression.Lambda>(contains, parameter); } Как подсказывает в комментарии @Pavel Mayorov, последнюю функцию можно переписать проще: Expression> GetContains(string propName, string value) { var parameter = Expression.Parameter(typeof(T), "t"); var prop = Expression.Property(parameter, propName); var valueAsExpr = Expression.Constant(value, typeof(string)); var contains = Expression.Call(prop, "Contains", null, valueAsExpr); return Expression.Lambda>(contains, parameter); }

Ответ 2



Исходный код у меня получился такой if (!string.IsNullOrEmpty(EventName)) { query = query.ContainsOrStartWithQuery(x => x.EventName, EventName); } if (!string.IsNullOrEmpty(Venue)) { query = query.ContainsOrStartWithQuery(x => x.VenueName, Venue); } Сам метод находится в статическом классе, он получился довольно большим. public static class ExpressionHelper { #region EgorAdded private static MethodInfo containsMethod; private static MethodInfo startsWithMethod; static ExpressionHelper() { containsMethod = typeof(string).GetMethods().First(m => m.Name == "Contains" && m.GetParameters().Length == 1); startsWithMethod = typeof(string).GetMethods().First(m => m.Name == "StartsWith" && m.GetParameters().Length == 1); } public static Expression> AddContains(this Expression> selector, string value) { var body = selector.GetBody().AsString(); var x = Expression.Call(body, containsMethod, Expression.Constant(value)); LambdaExpression e = Expression.Lambda(x, selector.Parameters.ToArray()); return (Expression>)e; } public static Expression> AddStartsWith(this Expression> selector, string value) { var body = selector.GetBody().AsString(); var x = Expression.Call(body, startsWithMethod, Expression.Constant(value)); LambdaExpression e = Expression.Lambda(x, selector.Parameters.ToArray()); return (Expression>)e; } private static Expression GetBody(this LambdaExpression expression) { Expression body; if (expression.Body is UnaryExpression) body = ((UnaryExpression)expression.Body).Operand; else body = expression.Body; return body; } private static Expression AsString(this Expression expression) { if (expression.Type == typeof(string)) return expression; MethodInfo toString = typeof(SqlFunctions).GetMethods().First(m => m.Name == "StringConvert" && m.GetParameters().Length == 1 && m.GetParameters()[0].ParameterType == typeof(double?)); var cast = Expression.Convert(expression, typeof(double?)); return Expression.Call(toString, cast); } public static IQueryable ContainsOrStartWithQuery(this IQueryable query, Expression> selector, string search) { if (search.StartsWith("*")) { search = search.Substring(1); query = query.Where(selector.AddContains(search)); } else { query = query.Where(selector.AddStartsWith(search)); } return query; } } https://stackoverflow.com/questions/16460057/call-contains-method-in-linq-to-entities-expression-on-a-type-other-than-strin Руководствовался этим вопросом

вторник, 17 декабря 2019 г.

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

#запрос #mysql


Есть такой запрос
SELECT SUM(`total`) AS `sum`,CONCAT_WS('-',year(FROM_UNIXTIME(`unix`)),DATE_FORMAT(FROM_UNIXTIME(`unix`),'%m'))
AS `key` FROM `shop_orders` WHERE `status` NOT IN (1,6) AND `unix` BETWEEN ".(int)$start."
AND ".(int)$end." GROUP BY `key`

Возвращает он массив данных формата [2012-08] => 4252.00
В переменных $start и $end unix-даты начала августа 2011 и конца августа 2012 соответственно.
Если в БД нет записей с датой какого-нибудь месяца, то ключ с этой датой естественно
отсутствует, это логично.
Вопрос: возможно ли перестроить запрос таким образом, чтоб ключи были в любом случае,
а если данные отсутствуют, то значение было 0?
Пример (при отсутствии данных в БД за апрель и июнь):
[2012-04] => 0
[2012-05] => 152.00
[2012-06] => 0
[2012-07] => 5721.00
[2012-08] => 4252.00
    


Ответы

Ответ 1



Воспользуйтесь ф-цией IFNULL()

суббота, 14 декабря 2019 г.

SQL-запрос, выводящий max(count(…)) и другие поля таблицы, соответствующие max-параметру

#запрос #sql


Имеются следующие таблицы:
Person(поля Nom и др.) - информация о людях,
Profit(поля ID, Source, Moneys) - источники дохода,
Have_d(поля Nom, ID и др.) - связь между людьми и их доходами.

Каждый человек может иметь несколько источников дохода.
Необходимо вывести всю информацию о самом популярном источнике дохода. То есть необходимо
подсчитать количество включений всех видов доходов, выбрать максимальное и вывести
полученное число вместе со всеми полями таблицы Profit, соответствующими полученному
максимуму.
Я смогла вывести максимальное число, но не получается составить запрос на вывод строки
из Profit, ему соответствующей.
    select max(expr1)
    from (select count(nom) as expr1
        from profit, have_d, person
        where profit.id = have_d.id 
        and have_d.nom = person.nom
        group by source)
    


Ответы

Ответ 1



Проблема известная. :-) Здесь найдете решение.

Ответ 2



Спасибо за ссылку. Теперь в нужном виде запрос выглядит так: select top 1 t1.* from (select profit.source,count(*) as expr1 from profit, have_d where profit.id = have_d.id group by profit.source) as t1 order by expr1 desc

Ответ 3



select t1.* from (select profit.*,count(*) as expr1 from profit, have_d where profit.id = have_d.id group by profit.id order by expr1 desc) as t1 limit 1 Я уверен есть решение лучше (скажем без limit). Таблица person не нужна.