Я пытаюсь анализировать твиты, используя назначенные вручную категории.Все хранится в базе данных MySQL.Я могу добавлять и удалять твиты, категории и отношения между ними без каких-либо проблем.
Включение категорий с использованием логики ИЛИ работает, как и ожидалось.Если я хочу найти твиты, классифицированные как «Венесуэла» или «Мадуро», я отправляю эти два термина в массив под названием $include
с $include_logic
, установленным на "or"
.Твиты, отнесенные к любой категории, возвращаются.Отлично!
Проблемы начинаются, когда я пытаюсь использовать логику AND (т. Е. Твиты, отнесенные к all включенным терминам, например, как Венесуэла и Maduro) или когдаЯ пытаюсь исключить категории.
Вот код:
function filter_tweets($db, $user_id, $from_utc, $to_utc, $include = null, $include_logic = null, $exclude = null) {
$include_sql = '';
if (isset($include)) {
$include_sql = 'AND (';
$logic_op = '';
foreach ($include as $cat) {
$include_sql .= "{$logic_op}cats.name = '$cat' ";
$logic_op = ($include_logic != 'and') ? 'OR ' : 'AND '; # AND doesn't work here
}
$include_sql .= ')';
}
$exclude_sql = ''; # Nothing I've tried with this works.
$sql = "
SELECT DISTINCT tweets.id FROM tweets
LEFT OUTER JOIN tweets_cats ON tweets.id = tweets_cats.tweet_id
LEFT OUTER JOIN cats ON tweets_cats.cat_id = cats.id
WHERE tweets.user_id = $user_id
AND created_at
BETWEEN '{$from_utc->format('Y-m-d H:i:s')}'
AND '{$to_utc->format('Y-m-d H:i:s')}'
$include_sql
$exclude_sql
ORDER BY tweets.created_at ASC;";
return db_fetch_all($db, $sql);
}
, где db_fetch_all()
- это
function db_fetch_all($con, $sql) {
if ($result = mysqli_query($con, $sql)) {
$rows = mysqli_fetch_all($result);
mysqli_free_result($result);
return $rows;
}
die("Failed: " . mysqli_error($con));
}
, а tweets_cats
- это таблица соединений между tweets
и cats
таблиц.
После прочтения таблиц соединений и соединений я понимаю, почему мой код не работает в двух упомянутых случаях.Он может просматривать только один твит и соответствующую категорию за раз.Поэтому просьба опустить твит, классифицированный как «X», является спорным, потому что он не пропустит его, когда встречается тот же твит, и классифицируется как «Y».
Что я не понимаю, так это как изменитькод, чтобы он работал.Я не нашел примеров людей, пытающихся сделать что-то подобное.Возможно, я не ищу правильные термины.Буду признателен, если кто-нибудь подскажет мне хороший ресурс для работы с соединительными таблицами в MySQL, аналогичный тому, как я их использую.
Редактировать : Вот рабочий SQLсозданная функцией с использованием вышеупомянутого примера, включая «Венесуэла» ИЛИ «Мадуро» в учетной записи VP в Твиттере с диапазоном дат, установленным на твиты в этом месяце (EST конвертируется в UTC).
SELECT DISTINCT tweets.id FROM tweets
LEFT OUTER JOIN tweets_cats ON tweets.id = tweets_cats.tweet_id
LEFT OUTER JOIN cats ON tweets_cats.cat_id = cats.id
WHERE tweets.user_id = 818910970567344128
AND created_at BETWEEN '2019-02-01 05:00:00' AND '2019-03-01 05:00:00'
AND (cats.name = 'Venezuela' OR cats.name = 'Maduro' )
ORDER BY tweets.created_at ASC;
Обновление : Вот рабочий SQL, который придерживается логики AND для включенных категорий.Большое спасибо @Strawberry за предложение!
SELECT tweets.id FROM tweets
LEFT OUTER JOIN tweets_cats ON tweets.id = tweets_cats.tweet_id
LEFT OUTER JOIN cats ON tweets_cats.cat_id = cats.id
WHERE tweets.user_id = 818910970567344128
AND created_at BETWEEN '2019-02-01 05:00:00' AND '2019-03-01 05:00:00'
AND cats.name IN ('Venezuela', 'Maduro')
GROUP BY tweets.id
HAVING COUNT(*) = 2
ORDER BY tweets.created_at ASC;
Хотя это немного выходит за рамки моего понимания SQL.Я рад, что это работает.Хотелось бы, чтобы я понял, как.
Обновление 2 : Вот рабочий SQL, исключающий категории.Я понял, что логика И / ИЛИ, которая применяется к включенным категориям, также относится к исключенным.В этом примере используется логика ИЛИ.Синтаксис, по сути, Q1 NOT IN (Q2), где Q2 - это то, что исключено, и это в основном тот же запрос, что и для включения.
SELECT id FROM tweets
WHERE user_id = 818910970567344128
AND created_at BETWEEN '2019-02-01 05:00:00' AND '2019-03-01 05:00:00'
AND id NOT IN (
SELECT tweets.id FROM tweets
LEFT OUTER JOIN tweets_cats ON tweets.id = tweets_cats.tweet_id
LEFT OUTER JOIN cats ON tweets_cats.cat_id = cats.id
WHERE tweets.user_id = 818910970567344128
AND created_at BETWEEN '2019-02-01 05:00:00' AND '2019-03-01 05:00:00'
AND cats.name IN ('Venezuela','Maduro')
)
ORDER BY created_at ASC;
Обновление 3 : Вотрабочий код.
function filter_tweets($db, $user_id, $from_utc, $to_utc,
$include = null, $include_logic = null,
$exclude = null, $exclude_logic = null) {
if (isset($exclude)) {
$exclude_sql = "
AND tweets.id NOT IN (\n"
. include_tweets($user_id, $from_utc, $to_utc, $exclude, $exclude_logic)
. "\n)";
} else {
$exclude_sql = '';
}
if (isset($include)) {
$sql = include_tweets($user_id, $from_utc, $to_utc, $include, $include_logic, $exclude_sql);
} else {
$sql = "
SELECT id FROM tweets
WHERE user_id = $user_id
AND created_at
BETWEEN '{$from_utc->format('Y-m-d H:i:s')}'
AND '{$to_utc ->format('Y-m-d H:i:s')}'
$exclude_sql";
}
$sql .= "\nORDER BY tweets.created_at ASC;";
return db_fetch_all($db, $sql);
}
, который использует эту дополнительную функцию для генерации SQL:
function include_tweets($user_id, $from_utc, $to_utc, $include, $logic, $exclude_sql = '') {
$group_sql = '';
$include_sql = 'AND cats.name IN (';
$comma = '';
foreach ($include as $cat) {
$include_sql .= "$comma'$cat'";
$comma = ',';
}
$include_sql .= ')';
if ($logic == 'and')
$group_sql = 'GROUP BY tweets.id HAVING COUNT(*) = ' . count($include);
return "
SELECT tweets.id FROM tweets
LEFT OUTER JOIN tweets_cats ON tweets.id = tweets_cats.tweet_id
LEFT OUTER JOIN cats ON tweets_cats.cat_id = cats.id
WHERE tweets.user_id = $user_id
AND created_at
BETWEEN '{$from_utc->format('Y-m-d H:i:s')}'
AND '{$to_utc ->format('Y-m-d H:i:s')}'
$include_sql
$group_sql
$exclude_sql";
}