2012-04-28 6 views
2

У меня есть запрос sql, где мне нравится получать полные записи.Mysql Я продолжаю получать полные рабочие места взамен

У меня есть один работодатель и 600 рабочих мест у этого работодателя.

Мне нужно получить все работодатели, но по какой-то причине мой запрос возвращает полные рабочие места, которые разместил работодатель.

Пожалуйста, дайте мне знать, что я не так в этом запросе.

SELECT count(c.id) as total 
FROM employer as c INNER JOIN job as j ON j.employerIDFK = c.id 
WHERE c.isActive=1 AND c.status=1 
AND j.isActive=1 
AND j.beenActive=1 
AND j.status=1 
AND DATE_ADD(j.createdAt, INTERVAL 30 DAY) > NOW() 
+1

Несколько вещей выпрыгнуть на меня по этому запросу. 1) Используйте правильные соединения. Неявные соединения вызывают массу проблем (я подозреваю, что это действительно связано с этим). 2) Предварительно рассчитайте СЕЙЧАС() - 30 дней, а затем используйте это значение для сравнения с j.createdAt. Таким образом, вы можете избежать полного сканирования таблицы (если j.createdAt проиндексирован). – Corbin

+0

Мне нужно получить полный список вакансий, которые еще менее 30 дней. Я не знаю, что вы подразумеваете под Precalculate NOW()? – Lalajee

+0

Поскольку значение NOW() постоянно изменяется, MySQL должен сравнивать пересчет его для каждой строки. Это означает, что даже без DATE_ADD потребуется полное сканирование таблицы. В принципе, у вас есть это: 'a + b Corbin

ответ

2
SELECT COUNT(DISTINCT c.id) AS total 
FROM employer c 
JOIN job j 
ON  j.employerIDFK = c.id 
WHERE c.isActive = 1 
     AND c.status = 1 
     AND j.isActive = 1 
     AND j.beenActive = 1 
     AND j.status = 1 
     AND j.createdAt >= NOW() - INTERVAL 30 DAY 

Создайте следующие индексы:

employer (isActive, status) 
job (employerFKID) 
job (isActive, beenActive, status, createdAt, employerFKID) 

для запроса работать быстрее.

Если по некоторым непонятным причинам вы не желаете использовать DISTINCT, вы можете использовать это:

SELECT COUNT(c.id) AS total 
FROM employer c 
WHERE c.isActive = 1 
     AND c.status = 1 
     AND c.id IN 
     (
     SELECT employerIDFK 
     FROM job j 
     WHERE j.isActive = 1 
       AND j.beenActive = 1 
       AND j.status = 1 
       AND j.createdAt >= NOW() - INTERVAL 30 DAY 
     ) 

, однако, это может быть менее эффективным, так как MySQL не может сделать job ведущим в этом виде запроса.

+0

Это действительно работает. Сейчас я получаю только 1 запись, которая правильна. но это можно сделать без DISTINCT – Lalajee

+1

@ Lalajee: что у вас есть против 'DISTINCT'? – Quassnoi

+0

в прошлом было сказано избежать этого. – Lalajee

1

Я подозреваю, что «SELECT count (*) как итог» является вашей проблемой. Вы просите SQL считать все, что возвращается. Следите за тем, что вы «SELECT», потому что это единственное, что будет возвращено вам.

Вы не совсем объяснили, чего вы пытаетесь достичь здесь. «Мне нужно, чтобы все работодатели были расплывчаты и трудно понять. Какие данные вы пытаетесь получить от работодателей? Их идентификатор? Их общая работа?

+0

Это всего лишь полные записи для моей разбивки на страницы. Мне нужно попросить систему вернуть общее число работодателей, у которых есть рабочие места на месте. – Lalajee

2

Ваш запрос должен возвращать счет для всех рабочих мест для всех работодателей, но есть некоторые критерии, которые они должны соответствовать, чтобы появиться. Неявное соединение, поскольку вы используете, является INNER JOIN. Для этого необходимо, чтобы все критерии соответствовали, чтобы строки были включены. Это означает, что он возвращает только рабочие места, которые являются «isActive», «aActive», «status = 1» и createdAt менее 30 дней в прошлом, где работодатели «isActive» и «status = 1». Проверьте свои данные, чтобы убедиться, что это именно то, что вы хотите.

SELECT c.id AS employerID, count(*) as total 
FROM employer as c, job as j 
WHERE c.isActive=1 AND c.status=1 
AND j.employerIDFK = c.id 
AND j.isActive=1 
AND j.beenActive=1 
AND j.status=1 
AND DATE_ADD(j.createdAt, INTERVAL 30 DAY) > NOW() 
GROUP BY c.id 

Насколько то, что другие пытаются сказать по поводу фильтра на createdAt, MySQL будет первым оценить NOW() (только один раз). Затем он добавляет 30 дней к каждой созданной дате, чтобы узнать, больше ли это, чем NOW(). MySQL иногда автоматически оптимизирует это, и это зависит от вашей версии и некоторых других факторов, но в целом выполнение функции против даты createdAt для каждой строки, чтобы сравнить ее с постоянным выражением, плохо, потому что MySQL не может использовать индекс на столбец createdAt.

Итак, вы должны преобразовать:

AND DATE_ADD(j.createdAt, INTERVAL 30 DAY) > NOW() 

Для этого:

AND j.createdAt > DATE_ADD(NOW(), INTERVAL -30 DAY) 

Это оставляет столбец j.createdAt как простой колонки, поэтому MySQL теперь может использовать любой индекс по отношению к колонке, чтобы найти даты, которые были менее 30 дней в прошлом.

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

+0

Благодарим вас за исправление для моего значения даты. Извините, моя проблема в том, что мне нужно вернуть номера на работодателей, которые разместили работу, и они занимают менее 30 дней. Но я продолжаю получать 604 записи, где я должен получить только 1 запись, так как у меня только 1 работодатель на столе моего работодателя. – Lalajee

+0

У меня есть 604 рабочих места, которые размещены этим работодателем. – Lalajee

+0

@ Lalajee, я обновил свой ответ, чтобы представить аналогию. Куда делась ваша статья GROUP? – Ami