如何将行作为一个组进行查询?

时间:2011-12-11 10:50:12

标签: mysql database

我正在创建一个允许用户创建“群组个人资料”的应用程序。组配置文件代表一个或多个个人。在基本级别,我使用2个表:父表用于对配置文件进行分组,子表用于实际配置文件。假设配置文件具有年龄和性别详细信息,我将如何查询表以获取父表id的列表:

  • 只代表一个个人资料的群组个人资料?
  • 代表年龄在25到30岁之间的男性和女性的群组资料?
  • 代表超过2个个人资料的群组个人资料?

在某些时候,我认为我需要在父表id上执行GROUP BY,但是我有点迷失了如何检查组配置文件具有的配置文件数,如何满足配置文件中的某些条件(例如性别等。)。

以下是包含一些数据的示例表:

SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0;
SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0;
SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='TRADITIONAL';

DROP SCHEMA IF EXISTS `mydb` ;
CREATE SCHEMA IF NOT EXISTS `mydb` DEFAULT CHARACTER SET latin1 COLLATE latin1_swedish_ci ;
USE `mydb` ;

-- -----------------------------------------------------
-- Table `mydb`.`foo_parent`
-- -----------------------------------------------------
DROP TABLE IF EXISTS `mydb`.`foo_parent` ;

CREATE  TABLE IF NOT EXISTS `mydb`.`foo_parent` (
  `foo_parent_id` INT NOT NULL AUTO_INCREMENT ,
  PRIMARY KEY (`foo_parent_id`) )
ENGINE = InnoDB;


-- -----------------------------------------------------
-- Table `mydb`.`foo`
-- -----------------------------------------------------
DROP TABLE IF EXISTS `mydb`.`foo` ;

CREATE  TABLE IF NOT EXISTS `mydb`.`foo` (
  `foo_id` INT NOT NULL AUTO_INCREMENT ,
  `foo_parent_id` INT NOT NULL ,
  `name` CHAR(50) NOT NULL ,
  `gender` ENUM('male','female') NOT NULL ,
  `age` INT NOT NULL ,
  PRIMARY KEY (`foo_id`) ,
  INDEX `foo_foo_parent_id` (`foo_parent_id` ASC) ,
  CONSTRAINT `foo_foo_parent_id`
    FOREIGN KEY (`foo_parent_id` )
    REFERENCES `mydb`.`foo_parent` (`foo_parent_id` )
    ON DELETE NO ACTION
    ON UPDATE NO ACTION)
ENGINE = InnoDB;



SET SQL_MODE=@OLD_SQL_MODE;
SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS;
SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS;

-- -----------------------------------------------------
-- Data for table `mydb`.`foo_parent`
-- -----------------------------------------------------
START TRANSACTION;
USE `mydb`;
INSERT INTO `mydb`.`foo_parent` (`foo_parent_id`) VALUES (1);
INSERT INTO `mydb`.`foo_parent` (`foo_parent_id`) VALUES (2);

COMMIT;

-- -----------------------------------------------------
-- Data for table `mydb`.`foo`
-- -----------------------------------------------------
START TRANSACTION;
USE `mydb`;
INSERT INTO `mydb`.`foo` (`foo_id`, `foo_parent_id`, `name`, `gender`, `age`) VALUES (1, 1, 'John Doe', 'male', 31);
INSERT INTO `mydb`.`foo` (`foo_id`, `foo_parent_id`, `name`, `gender`, `age`) VALUES (2, 1, 'Jane Doe', 'female', 29);
INSERT INTO `mydb`.`foo` (`foo_id`, `foo_parent_id`, `name`, `gender`, `age`) VALUES (3, 2, 'Billy Bob', 'male', 25);
INSERT INTO `mydb`.`foo` (`foo_id`, `foo_parent_id`, `name`, `gender`, `age`) VALUES (4, 2, 'Suzie', 'female', 27);

COMMIT;

示例查询和结果:

示例1:获取所有foo_parent.id,其中组配置文件所代表的配置文件包含“男性”,“女性”返回1和2.

示例2:获取所有foo_parent.id,其中由组配置文件表示的配置文件包含“男性”和“女性”,年龄介于20到30之间,返回2。

另外:如果这种分组和查询配置文件的方法存在明显的问题,请告诉我。

3 个答案:

答案 0 :(得分:0)

您可以尝试构建谓词计数,例如在内联视图中,“20到30之间的男性”或“20到30之间的女性”,然后在外部查询的where子句中引用它们。例如:

示例1:获取所有foo_parent.id,其中组配置文件表示的配置文件包含“male”,“female”返回1和2:

select t.foo_parent_id
from
(
select fp.foo_parent_id,
sum(case when f.gender = 'Male' then 1 else 0 end) as males,
sum(case when f.gender = 'Female' then 1 else 0 end) as females,
sum(case when f.gender = 'Male' and f.age between 20 and 30 then 1 else 0 end) as twenties_males,
sum(case when f.gender = 'Female' and f.age between 20 and 30 then 1 else 0 end) as twenties_females
from foo_parent fp
left outer join foo f on f.foo_parent_id = fp.foo_parent_id
group by fp.foo_parent_id
) t
where t.males > 0 and t.females > 0;

示例2:获取所有foo_parent.id,其中由组配置文件表示的配置文件包含“男性”和“女性”,年龄介于20和30之间,返回2:

select t.foo_parent_id
from
(
select fp.foo_parent_id,
sum(case when f.gender = 'Male' then 1 else 0 end) as males,
sum(case when f.gender = 'Female' then 1 else 0 end) as females,
sum(case when f.gender = 'Male' and f.age between 20 and 30 then 1 else 0 end) as twenties_males,
sum(case when f.gender = 'Female' and f.age between 20 and 30 then 1 else 0 end) as twenties_females
from foo_parent fp
left outer join foo f on f.foo_parent_id = fp.foo_parent_id
group by fp.foo_parent_id
) t
where t.twenties_males > 0 and t.twenties_females > 0;

我在这些查询中包含了foo_parent表,以防你想要包含“20到40之间没有男性或女性”之类的东西。

答案 1 :(得分:0)

另一种方法是为您查询的每组数据创建别名(在本例中为性别),然后按照以下示例加入同一组:

select
  grp.foo_parent_id
from
  foo m
  ,foo f
  ,foo_parent grp
where
  m.foo_parent_id = grp.foo_parent_id
  and f.foo_parent_id = grp.foo_parent_id
  and m.gender = 'male'
  and f.gender = 'female'


select
  grp.foo_parent_id
from
  foo m
  ,foo f
  ,foo_parent grp
where
  m.foo_parent_id = grp.foo_parent_id
and f.foo_parent_id = grp.foo_parent_id
and m.gender = 'male'
and f.gender = 'female'
and m.age between 20 and 30
and f.age between 20 and 30

答案 2 :(得分:-1)

对于:示例1:获取所有foo_parent.id,其中由组配置文件表示的配置文件包含“男性”,“女性”返回1和2.

SELECT f.foo_parent_id
FROM (
    SELECT f.foo_parent_id, f.gender
    FROM mydb.foo AS f
    GROUP BY f.foo_parent_id, f.gender
) AS f
GROUP BY f.foo_parent_id
HAVING COUNT(f.foo_parent_id) >= 2;

对于:示例2:获取所有foo_parent.id,其中由组配置文件表示的配置文件包含“男性”和“女性”,年龄介于20到30之间,返回2。

SELECT f.foo_parent_id
FROM (
    SELECT f.foo_parent_id, f.gender
    FROM mydb.foo AS f
    WHERE f.age BETWEEN 20 AND 30
    GROUP BY f.foo_parent_id, f.gender
) AS f
GROUP BY f.foo_parent_id
HAVING COUNT(f.foo_parent_id) >= 2;
但是,我不确定这是最好的方法。

对于:代表两个以上个人资料的群组配置文件?

SELECT f.foo_parent_id
FROM mydb.foo AS f
GROUP BY f.foo_parent_id
HAVING COUNT(*) > 2;