Запрос таблицы с массивом объектов json в RedbeanPHP - PullRequest
0 голосов
/ 12 декабря 2018

У меня проблемы с работой в Redbean PHP с запросом таблицы с массивом объектов json в одном поле и созданием отчета по ней.

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

У меня есть база данных с:

table clients
with columns:(int) client_id, (string) client_name, (array of json) notes
notes is an array of json with 
(int) note_id, (int) note_category_id, (int) staff_id, (string) description, (memo) content, (date) note_date

table staff with columns (int) sid, (string) sname

table categories with columns (int) cat_id, (string) cat_name

Так что в псевдокоде (так как я все еще пытаюсь все это выяснить) мне нужно выполнить запрос вроде: (с параметрами вквадратные скобки)

R::getAll('Select * from Join (staff, categories, clients) 
On (staff.sid=clients.services.staff_id, categories.cat_id=clients.services.note_category_id)
Where (clients.services.note_date Between [startdate] and [enddate], 
  categories.cat_name IN [chosencateg], staff.sname IN [pickednames])
Orderby sname Asc, cat_name Asc, note_date Desc ');

формат вывода отчета:

Filters used: [picked filter choices if any]
-----------
[sname]
--  note category: [cat_name] 1
        [note_date] 1   [description] 1 [content] 1
        [note_date] 2   [description] 2 [content] 2
    note category 1 subtotal
--  note category: [cat_name] 2
        [note_date] 3   [description] 3 [content] 3
        [note_date] 4   [description] 4 [content] 4
    note category 2 subtotal
staff subtotal
[sname] 2 ...

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

Спасибо за любую помощь.

Ответы [ 2 ]

0 голосов
/ 24 января 2019

Итак, я решил, что хочу этого в MySQL (5.7), чтобы использовать его возможности.Для этого я использовал манипуляции со строками.MySQL 8 добавляет функции json_table, которые было бы неплохо иметь.

Я преобразовал каждый массив заметок JSON в строки INSERT INTO temptable, чтобы преобразовать список массивов в строки, подлежащие изменению, по одному объекту JSON на строку, добавив client_id к каждому объекту, а затем ВЫПОЛНЯЯ эти операторы.

SET @allnotes = (
SELECT json_arrayagg(REPLACE(`notes`,'{', CONCAT('{"id_client": ', id_client, ', ')))   /* add id_client to each note object */
FROM clients
WHERE `notes` != '' AND `notes` != '[]' );                      /* no empty note cases */
SET @allnotes = REPLACE(REPLACE(@allnotes ,'"[',''),']"','' );      /* flatten out outer array of each note */
SET @allnotes = REPLACE(REPLACE(@allnotes ,'{','("{'),'}','}")' );  /* INSERT INTO string formatting for the objects */

DROP TEMPORARY TABLE IF EXISTS jsonTemporary;
CREATE TEMPORARY TABLE IF NOT EXISTS jsonTemporary (anote json);
SET @allnotes = REPLACE(REPLACE(@allnotes,'[','INSERT INTO jsonTemporary (anote) VALUES '),']',';');

PREPARE astatement FROM @allnotes;
EXECUTE astatement;

/* totals */
SELECT concat(staff.last_name,", ",staff.first_name) AS sname,
categories.name AS cat_name,
count(anote->'$.id_client') AS cat_total,
FROM jsonTemporary
JOIN categories ON cast(anote->'$.note_category_id' as unsigned)=categories.id
JOIN clients ON clients.id_client=anote->'$.id_client'
JOIN staff ON staff.id=anote->'$.staff_id'
WHERE anote->'$.note_date' >= "2018-10-01" AND anote->'$.note_date' <= "2018-12-31"
GROUP BY sname, cat_name;

/* all notes */
SELECT concat(staff.last_name,", ",staff.first_name) AS sname,
categories.name AS cat_name,
anote->'$.note_date' AS n_date,
anote->'$.description' AS description,
anote->'$.content' AS content,
FROM jsonTemporary
JOIN categories ON cast(anote->'$.note_category_id' as unsigned)=categories.id
JOIN clients ON clients.id_client=anote->'$.id_client'
JOIN staff ON staff.id=anote->'$.staff_id'
WHERE anote->'$.note_date' >= "2018-10-01" AND anote->'$.note_date' <= "2018-12-31"
GROUP BY sname, cat_name;

DROP TEMPORARY TABLE IF EXISTS jsonTemporary;
0 голосов
/ 13 декабря 2018

redbean - это фантастика, и - getAll просто царапает поверхность и на самом деле совсем не работает с redbean ... Читайте об этом здесь :

Вот шаблон запросадля начала:

Шаблон запроса:

1)

R::getAll('Select * from Join (staff, categories, clients) 
On (staff.sid=clients.services.staff_id, categories.cat_id=clients.services.note_category_id)
Where (clients.services.note_date Between :startdate and :enddate, 
  categories.cat_name IN (:chosencateg), staff.sname IN (:pickednames))
Orderby sname Asc, cat_name Asc, note_date Desc ');

Вы также можете просто использовать:

2)

R::getAll('Select * from Join (staff, categories, clients) 
On (staff.sid=clients.services.staff_id, categories.cat_id=clients.services.note_category_id)
Where (clients.services.note_date Between ? and ?, 
  categories.cat_name IN (?), staff.sname IN (?))
Orderby sname Asc, cat_name Asc, note_date Desc ');

Единственное отличие состоит в том, что шаблон запроса 1 использует именованные параметры (поэтому он будет смотреть на массив параметров, который вы передадите, чтобы он содержал ассоциативный массив с параметрами, названными так же, как и в запросе).В то время как шаблон 2 требует просто массив параметров с индексами, выстроенными в порядке, в котором?отметки появляются в вашем запросе.

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

Array
(
[client_id] => 1,
[client_name] => "joe",
[noes] => "[
           {note_id=1
           ,note_category_id=1
           ,staff_id=1
           ,description=blah blah
           ,content=blah blah blah blah
           ,content=some content for this note
           ,note_date=12/06/2018
           }
           ]"
[sid] => 100,
[sname] => "some staff name"
[cat_id] => 100
[cat_name] => "some category name"
)

Обратите внимание, что поле примечаний только что вышло в виде строки (я знаю, что json выше не является правильно сформированным json, я просто пытаюсь показать пример).

Я предполагаю, что вам нужно преобразовать эту строку в массив, чтобы вы могли работать с ней, как если бы это были данные, а не строка.Таким образом, ниже следует начать с этого:

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

$result = R::getAll($query,
['startdate'=> $mystartDate
,'enddate' => $myEndDate
,'chosencateg'=>$myChosenCategory
,'pickednames'=>$myPickedNames
]);
// this would output the json string to your screen
echo $result['notes'];

но похоже, что вы хотитеработать с json, как если бы он был частью ваших данных - так что ... вам нужно сначала его декодировать.

// decode my notes field:
foreach(array_key($result) as $key) {
/* you are working with a multidimensional array in this loop
, use $key to access the row index. Each row index 
will contain named column indexes that are column names from the database
*/
$result[$key]['decoded_notes'] = json_decode($result[$key]['notes'],true);
}
// I now have a new column in each row index, containing 'notes' 

как другой ассоциативный массив

// the statement below now results in an array to string conversion error:
echo $result[someIndexNumber]['decoded_notes'];
...