Search code examples
sqlduplicatesrow

SQL Query to create duplicate rows of data


I have a SQL table that gives me people names, pets and pets age. As per picture 1: Picture 1 The distinct type of pets are: Picture 2 What I would like to be able to do is produce a query which returns all people, ALL pets (even if they don’t have that pet) and the pets age (returning a null value if they don’t have that pet). See picture 3. Picture 3 I have tried a few things but to no avail.

Any ideas please?


Solution

  • I believe I am understanding this correctly. Ideally you would have separate tables for the "pet_types" and then you would have a table for "peoples_pets". Or you could even do 3 tables "pet_types","people", "peoples_pets" joining on foreign keys to access said data.

    With that being said in your current setup this is one way of doing it using temp tables to separate the data and join it back together. I first grab the distinct pet values, then the people, then I get the raw data. I join those together with a id of 1. Then using a case statement I link the users pet to them and sum the age of it(to help the group by). This group by is done by person and pet.

    This assumes you are using MySQL and not MSSQL etc. If you are using one of those, you can convert this into what you need. Logic should be relatively the same:

    
    CREATE DATABASE  IF NOT EXISTS `test` /*!40100 DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci */ /*!80016 DEFAULT ENCRYPTION='N' */;
    USE `test`;
    
    
    /*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
    /*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
    /*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
    /*!50503 SET NAMES utf8 */;
    /*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
    /*!40103 SET TIME_ZONE='+00:00' */;
    /*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
    /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
    /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
    /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
    
    --
    -- Table structure for table `person_pets`
    --
    
    DROP TABLE IF EXISTS `person_pets`;
    /*!40101 SET @saved_cs_client     = @@character_set_client */;
    /*!50503 SET character_set_client = utf8mb4 */;
    CREATE TABLE `person_pets` (
      `id` int NOT NULL AUTO_INCREMENT,
      `person` varchar(45) DEFAULT NULL,
      `pet` varchar(45) DEFAULT NULL,
      `pet_age` varchar(45) DEFAULT NULL,
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=23 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
    /*!40101 SET character_set_client = @saved_cs_client */;
    
    --
    -- Dumping data for table `person_pets`
    --
    
    LOCK TABLES `person_pets` WRITE;
    /*!40000 ALTER TABLE `person_pets` DISABLE KEYS */;
    INSERT INTO `person_pets` VALUES (1,'Max','Dog','2'),(2,'Max','Cat','6'),(3,'Max','Snake',NULL),(4,'Max','Hamster',NULL),(5,'June','Dog','8'),(6,'June','Cat',NULL),(7,'June','Snake',NULL),(8,'June','Hamster','2'),(9,'Chris','Dog',NULL),(10,'Chris','Cat','4'),(11,'Chris','Snake',NULL),(12,'Chris','Hamster',NULL),(13,'Ryan','Dog',NULL),(14,'Ryan','Cat',NULL),(15,'Ryan','Snake','1'),(16,'Ryan','Hamster',NULL),(17,'Jen','Dog',NULL),(18,'Jen','Cat',NULL),(19,'Jen','Snake',NULL),(20,'Jen','Hamster','1'),(21,'James','Cat','1'),(22,'James','Snake','3');
    /*!40000 ALTER TABLE `person_pets` ENABLE KEYS */;
    UNLOCK TABLES;
    /*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
    
    /*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
    /*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
    /*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
    /*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
    /*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
    /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
    /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
    
    
    --SOLUTION!!!!!
    
    
    
    use test;drop temporary table if exists pets; create temporary table pets 
    select distinct
    1 as id,
    p1.pet
    from test.person_pets p1;
    
    drop temporary table if exists people; create temporary table people 
    select distinct
    1 as id,
    p2.person
    from test.person_pets p2;
    
    drop temporary table if exists raw_data; create temporary table raw_data 
    select distinct
    1 as id,
    p3.person,
    p3.pet,
    p3.pet_age
    from test.person_pets p3;
    
    
    SELECT DISTINCT
        pp.person,
        pt.pet,
        SUM(CASE
            WHEN
                rd.person = pp.person
                    AND pt.pet = rd.pet
            THEN
                rd.pet_age
        END) AS 'age'
    FROM
        people pp
            JOIN
        pets pt ON pp.id = pt.id
            JOIN
        raw_data rd ON pp.id = rd.id
    GROUP BY pp.person , pt.pet