INSERT INTO, Multiple WHERE IN, Check if value exist - php

I am collecting information about 30 posts with title and content in a multidimensional array which is relatively long and then put all of them into database by one MySQL query. But my checking query is separate from that inserting. I am checking similar post by the new post's title and then insert it. How can I merge the checking query with the inserting one?
This is my multidimensional array about 30 posts :
array(
[0] => array(
[post_title] => $postTitle1,
[post_content] => $contentTitle1,
)
[1] => array(
[post_title] => $postTitle2,
[post_content] => $contentTitle2,
)
[N] => array(
[post_title] => $postTitleN,
[post_content] => $contentTitleN,
)
);
This is my checking query by the new post's title (is done for each post and works fine):
SELECT post_title FROM x_post WHERE post_title=$newPostTitle
This is my inserting query (works fine):
INSERT INTO x_post (`post_title`, `post_content`, `date_created`, `user_id`)
VALUES ((((( My multidimensional array's information will be here after processing )))))
and Finally this is the query what I want to have but it does not work (to merge two queries):
INSERT INTO x_post (`post_title`, `post_content`, `date_created`, `user_id`)
SELECT * FROM (SELECT $postTitle1, $content1, $time, $userId") AS tmp1, (SELECT $postTitle2, $content2, $time, $userId") AS tmp2, .......... and so on ........... , (SELECT $postTitle30, $content30, $time, $userId") AS tmp30 WHERE NOT EXIST (SELECT x_post.post_title FROM x_post WHERE x_post.post_title IN ($newPostTitle1, $newPostTitle2, ... and so on... , $newPostTitleN))
What is the best way to write the query ?
In fact I want to check all the 30 posts if similar is exist in one query and then insert those has not similar.
I know it is complicated, but would be a great query.
Thanks a lot.

You can use UNION ALL to make a set of your individual FROM-less SELECTs which you can then use as just one derived table instead of 30. And instead of using IN in the WHERE clause you can just correlate directly.
INSERT INTO x_post
(`post_title`,
`post_content`,
`date_created`,
`user_id`)
SELECT `post_title`,
`post_content`,
`date_created`,
`user_id`
FROM (SELECT $postTitle1 `post_title`,
$content1 `post_content`,
$time `date_created`,
$userId `user_id`
UNION ALL
...
UNION ALL
SELECT $postTitle30 `post_title`,
$content30 `post_content`,
$time `date_created`,
$userId `user_id`) tmp
WHERE NOT EXISTS (SELECT *
FROM x_news
WHERE x_news.news_title = tmp.`post_title`);

Related

How to manipulate and collate data in an associate array

I have the following array of data
2889 1 1062
2889 8 John Smith
2889 6 0.29
2891 1 1117
2891 8 Jamie Dean
2891 6 2
2892 1 1062
2892 8 John Smith
2892 6 4
The First column is a list of entry IDs relating to form entries from a website, the second column is a list of meta_keys relating to fields in the form, and the final column is the data from those fields.
What I need to be able to do is collate the data in the array so that for each person I have:
ID Number(Meta_key 1)
Name(Meta_key 8)
Sum(Hours Owed(Meta_key 6))
I am lost on how to even start this task, any help would be very much appreciated.
This data has all been pulled from a database with the following query:
select
entry_id,
meta_key,
meta_value
from
staff_gf_entry_meta
where
form_id = 48
and
entry_id in (
select
entry_id
from
staff_gf_entry_meta
where
meta_key = 7
and
form_id = 48
and
meta_value <= '2018-12-18'
and
meta_value >= '2018-12-12'
)
and (
meta_key = 1
or
meta_key = 8
or
meta_key = 6)
If needed the query can be altered.
You might want a GROUP BY statement with the SUM aggregate function. To get all the key/value pairs in a row, you need to JOIN multiple queries.
SELECT
`mk1`.`meta_value` `Number`,
`mk8`.`meta_value` `Name`,
SUM(`mk6`.`meta_value`) `Hours Owed`
FROM
`staff_gf_entry_meta` `mk1`
INNER JOIN
`staff_gf_entry_meta` `mk6`
USING
(`entry_id`, `form_id`)
INNER JOIN
`staff_gf_entry_meta` `mk7`
USING
(`entry_id`, `form_id`)
INNER JOIN
`staff_gf_entry_meta` `mk8`
USING
(`entry_id`, `form_id`)
WHERE
`mk1`.`meta_key` = 1
AND
`mk6`.`meta_key` = 6
AND
`mk7`.`meta_key` = 7
AND
`mk8`.`meta_key` = 8
AND
`mk1`.`form_id` = 48
AND
`mk7`.`meta_value` BETWEEN '2018-12-12' AND '2018-12-18'
GROUP BY `mk1`.`meta_value`,`mk1`.`form_id`
;
I've assumed the following table structure and data:
CREATE TABLE `staff_gf_entry_meta`
(
`form_id` int(11) NOT NULL,
`entry_id` int(11) NOT NULL,
`meta_key` int(11) NOT NULL,
`meta_value` varchar(45) DEFAULT NULL,
PRIMARY KEY (`entry_id`,`form_id`,`meta_key`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
;
INSERT INTO `staff_gf_entry_meta` (form_id, entry_id, meta_key, meta_value)
VALUES
(48, 2889, 1, 1062),
(48, 2889, 8, 'John Smith'),
(48, 2889, 6, 0.29),
(48, 2891, 1, 1117),
(48, 2891, 8, 'Jamie Dean'),
(48, 2891, 6, 2),
(48, 2892, 1, 1062),
(48, 2892, 8, 'John Smith'),
(48, 2892, 6, 4)
;
INSERT INTO `staff_gf_entry_meta`
SELECT DISTINCT form_id, entry_id, 7 meta_key, '2018-12-17' meta_value
FROM testdb.staff_gf_entry_meta
;
Result:
# Number, Name, Hours Owed
'1062', 'John Smith', '4.29'
'1117', 'Jamie Dean', '2'
Start with something like below, and build from there.
$meta_labels = [
1 => 'ID'
8 => 'name'
6 => 'hours'
];
$output = [];
foreach($results as result) {
$eid = $result['entry_id'];
$label = $meta_labels[$result['meta_key']];
$output[$eid][$label] = $result['meta_value'];
}
And ideally the mapping between metadata IDs and their labels should be stored in the database, not hard-coded in the application.

Group SQL query results by year

I'm new in SQL and I need to group the results of a query by year.
In other words, I have this table structure:
id | title | date
My current query SELECT * FROM table
My current result:
array =>
0 =>
array =>
...
'date' => string '2018-03-09'
1 =>
array =>
...
'date' => string '2018-03-15'
2 =>
array =>
...
'date' => string '2017-03-15'
And I need something like that:
array =>
0 =>
array =>
...
'date' => string '2018-03-09'
array =>
...
'date' => string '2018-03-15'
1 =>
array =>
...
'date' => string '2017-03-15'
Thanks in advance for help :)
[EDIT]
I finally found a way to do what I wanted:
$result = $sql->query("SELECT * FROM abstract ORDER BY date DESC");
$array = [];
forEach($result as $res) {
$year = strtok($res['date'], '-');
if (!isset($array[$year]))
$array[$year][0] = $res;
else
array_push($array[$year], $res);
}
return $array;
If you want group data by year.
Select id,title,date,DATE_FORMAT(date, '%Y') YEAR_GRP from table group by YEAR_GRP
This is something you'll want to do in your query, as MySQL can do it much more efficiently, than PHP.
The way to do it is to add a GROUP BY clause to your query, which will batch rows in your resultset into a single row, based on a grouping value, which in your case will be YEAR(date), as you're looking to group items by the year component in each line's date.
Because you're still looking to have all the results returned, merely grouped by each distinct grouping value, you'll need to use an Aggregate Function to combine all the matching lines into an array of values. Luckily MySQL has a function called json_objectagg which does exactly what you need.
So you'll end up with a query that looks something like:
SELECT year(`date`) AS `year`, json_objectagg(id, `date`, title) AS `line`
FROM abstract
GROUP BY `year`
Instead of json_objectagg, alternatives are e.g. json_arrayagg
SELECT year(`date`) AS `year`, json_arrayagg(id, `date`, title) AS `line`
...or group_concat
SELECT year(`date`) AS `year`, group_concat(id, `date`, title) AS `line`
...depending on what kind of output you require.

CakePHP : Get Table with many conditions

I have a very specific problem. Even with the great CakePHP doc, I still don't know how to fix my pb.
I'm currently web developping using the CakePHP framework. Here is my situation :
I have a Table "TableA" which contains parameters "name", "type"(1 to 6) and "state"(OK and NOT OK) . What I want is getting all the Table lines which are type 5 OR 6 and which have not a same name line with "state" OK.
There are different lines of the table which have the same "name". I'm interesting to the lines from the same name where there is no OK state.
For example, there are :
name : example1 state : NOT OK
name : example1 state : NOT OK
name : example1 state : NOT OK
And there is no example1 with the state OK and this is this kind of line I want to get.
I would like to do this with the cakePHP syntax, with conditions in the TableRegistry::get function.
Thanks for helping. Waiting for your return.
PS:
What I achieved now is not the best solution :
$tablea_NOTOK = TableRegistry::get("TableA")->find('all', array(
'conditions' => array(
'OR' => array(
array('TableA.type' => 5),
array('TableA.type' => 6),
),
'Etudes.state' => 'NOT OK'
)
));
$this->set(compact('tablea_NOTOK'));
$tablea_OK = TableRegistry::get("TableA")->find('all', array(
'conditions' => array(
'OR' => array(
array('TableA.type' => 5),
array('TableA.type' => 6),
),
'Etudes.state' => 'OK'
)
));
$this->set(compact('tablea_OK'));
And then in my view, i compared each line of the tablea_OK with the tablea_NOTOK. But there is a lot of data so the code is not perfect and slow
You may consider creating a view table in your database which holds the combination of data needed. Since the data will all be from a single table, you wouldn't need to loop through the data and compare it.
I don't know all your table relationships, but I made a simple table with these fields and data:
id name type state
1 Harry 5 OK
2 Harry 6 NOT OKAY
3 Harry 6 NOT OKAY
4 John 5 NOT OKAY
Then I wrote a query which would group by name and count the state values:
SELECT `name`, `type`, `state`,
(SELECT COUNT(state) FROM TableA as TableA1 WHERE `state` = 'OK' AND TableA.name = TableA1.name) as okay_count,
(SELECT COUNT(state) FROM TableA as TableA2 WHERE `state` = 'NOT OKAY' AND TableA.name = TableA2.name) as not_okay_count
FROM TableA
GROUP BY name;
The results look like this:
name type state okay_count not_okay_count
Harry 5 OK 1 2
John 5 NOT OKAY 0 1
You can adjust the query as needed and create your database view table and then call that in CakePHP.
$my_view_table = TableRegistry::get("MyViewTable")->find('all');
You can learn more about MySQL view tables here

Counting occurrences of a field based on another field

I'm trying to count a certain field and how much it occurs based on a date. For example, I have a reputation field that I need counted, so if there is 5 reputation points that were individually submitted on 12/14/2014, how would I get the total amount and not just 5 rows?
This is an example of what I am trying to do (if it helps explain it better)
'ID' => 1,
'rep' => 'SK01',
'25/11/14' => '5',
'26/11/14' => '23',
'27/11/14' => '3',
'28/11/14' => '87',
'29/11/14' => '4',
'01/12/14' => '45',
'02/12/14' => '145',
On today [ 2014-12-08 09:53:27 ] there were 1 for AH05 (I'm just getting a repeat of that however many times it is in table) Here is the SQL also if that helps
SELECT *, COUNT(*) as TotalValueCount, DATE(date_created) AS thedate
FROM wp_rg_lead INNER JOIN wp_rg_lead_detail ON wp_rg_lead.id = wp_rg_lead_detail.lead_id
WHERE wp_rg_lead.form_id = '47' AND date_created BETWEEN DATE_SUB(NOW(), INTERVAL 7 DAY)
AND NOW() AND field_number = '18' GROUP BY value, date_created
You would do a group by query, but the results would be in rows, not columns:
select rep, date, count(*)
from table t
group by rep, date;
If, for some reason, you really have to have the values in columns, I would suggest doing it at the application layer. Otherwise, Google "MySQL dynamic pivot" to get ideas on what to do.

Issue with UNION Query

I'm trying what seems to be a simple union query for two tables in my database though I am unable to retrieve a successful array result. It should be noted that each table has different columns and that I'd like to create a virtual result (promo AS origin [for the result pulled from the 'venpromo' table] && vacation AS origin [for the result pulled from the 'vacation' table]) in order to sort the results into different array structures. I've looked everywhere and UNIONS are all using different syntax. Thank you all in advance!
<?php
require_once('includes/config.php');
$event_query = "SELECT *, promo AS origin FROM venpromo
UNION
SELECT *, vacation AS origin FROM venpromo
ORDER BY popularity DESC";
$event_result = mysql_query($event_query, $connection);
while ($event = mysql_fetch_array($event_result)) {
if ($event['origin'] == "promo") {
$event_array[] = array(
'id' => $event['id'],
'title' => $event['calname'],
'start' => $event['sdate'],
'end' => $event['edate'],
'color' => "red",
'url' => "http://www.norrisportal.com/bulletinpost.php?id=" . $event['id'] . "&hashkey=akdULjsjyUpYyTzOT7"
);
} elseif ($event['origin'] == "vacation") {
$event_array[] = array(
'id' => $event['id'],
'title' => $event['reason'],
'start' => $event['vacstart'],
'end' => $event['vacend'],
'color' => "blue"
);
}
}
echo json_encode($event_array);
?>
When visiting the page to view the results, I see 'null'.
Put the columns names explicitly rather than *, and make sure the number of columns and data types match for the same column in each select.
I have added some dummy columns to match the number and data types in both the tables and also changed the order of the columns.
try this sample way ::
select
id,
uid,
approval,
vacstart,
vacend,
reason,
'dummy1' col1,
'dummy2' col2,
'dummy3' col3,
curdate() col4,
'dummy4' col5,
'dummy5' col6,
'dummy6' col7,
'dummy7' col8,
promo AS origin
from vacation
union
select
id,
venid,
authid,
sdate,
edate,
authname,
tags,
title,
calname,
date,
intro,
body,
sum,
sortdate,
vacation AS origin
from venpromo;

Categories