2
votes

Comment supprimer les données en double de BigQuery et les enregistrer dans une autre table comportant beaucoup d'attributs

J'ai importé les 99 628 lignes dans Google BigQuery. Le schéma a supposé, nom_entreprise, téléphone, e-mail, adresse, ville, état, etc. Je souhaite conserver uniquement des lignes distinctes par nom_entreprise avec la plupart des attributs. Si j'ai les lignes comme

Microsoft | 2355 |

Microsoft | 1234 | ms@example.com | seatle | XYZ | KC

Microsoft | 2355 | any@example.com

Je voudrais conserver la deuxième ligne, car elle a l'attribut le plus élevé.

J'ai essayé avec la requête ci-dessous mais elle ne me renvoie que résultats distincts pas un avec l'attribut le plus élevé.

SELECT *
FROM (
  SELECT
      *,
      ROW_NUMBER()
      OVER (PARTITION BY company_name)
      row_number
  FROM `local-bastion-154121.Property_Dataset.pmDATA`
)
WHERE row_number = 1


0 commentaires

3 Réponses :


0
votes

Vous pouvez créer une sous-requête comptant pour chaque ligne le nombre de colonnes remplies, puis vous triez:

SELECT *
FROM (
  SELECT
      *,
      ROW_NUMBER()
          OVER (PARTITION BY company_name ORDER BY columns_filled DESC)
          row_number
  FROM (
        SELECT *, 
        IF(uppose !="", 1,0) + IF(company_name !="", 1,0) + IF(phone !="", 1,0) + 
        IF(email !="", 1,0) + IF(address !="", 1,0) + IF(city !="", 1,0) + 
        IF(state !="", 1,0) + <SAME FOR EACH FIELD> as columns_filled
        FROM `local-bastion-154121.Property_Dataset.pmDATA`
   )
)
WHERE row_number = 1

C'est tout :)


0 commentaires

1
votes

J'interprète "avec l'attribut le plus élevé" comme signifiant la ligne avec le plus de valeurs non NULL pour un company_name particulier. Vous devriez pouvoir faire quelque chose comme ceci:

WITH existing_table AS (
  SELECT 'Microsoft' AS company_name, 2355 AS x, NULL AS email, NULL AS city, NULL AS y, NULL AS z UNION ALL
  SELECT 'Microsoft', 1234, 'ms@example.com', 'seattle', 'XYZ', 'KC' UNION ALL
  SELECT 'Microsoft', 2355, NULL, NULL, NULL, NULL
)
SELECT
  company_name,
  ARRAY_AGG(
    (SELECT AS STRUCT t.* EXCEPT (company_name))
    ORDER BY ARRAY_LENGTH(SPLIT(TO_JSON_STRING(t), ':null'))
  )[OFFSET(0)].*
FROM existing_table AS t
GROUP BY company_name

À titre d'exemple sur des exemples de données:

CREATE TABLE dataset.new_table AS
SELECT
  company_name,
  ARRAY_AGG(
    (SELECT AS STRUCT t.* EXCEPT (company_name))
    ORDER BY ARRAY_LENGTH(REGEXP_EXTRACT_ALL(TO_JSON_STRING(t), r': null'))
  )[OFFSET(0)].*
FROM dataset.existing_table AS t
GROUP BY company_name

L'avantage d'utiliser cette astuce et compter les valeurs NULL en utilisant SPLIT en conjonction avec TO_JSON_STRING , c'est que vous n'avez pas besoin d'écrire la liste des autres colonnes explicitement. Ce qu'il fait est de construire une structure de toutes les colonnes à l'exception de nom_colonne , et de trier par le nombre de valeurs NULL dans la ligne dans l'ordre croissant, ce qui signifie que vous obtenez le ligne avec les valeurs les plus renseignées pour chaque nom_entreprise.


1 commentaires

Merci! :) A parfaitement fonctionné.



1
votes

Je considérerais une traduction légèrement différente de "avec l'attribut le plus élevé" en introduisant un poids par champ, comme par exemple je m'attendrais à ce qu'avoir email soit plus important que city , state donc un seul champ surpondérerait deux champs pour moi

​​Voici pour BigQuery Standard SQL et tente une approche pondérée

Row company_name    phone   email           city    address state   score   
1   Microsoft       2355    any@example.com null    null    null    104  
2   Microsoft       1234    null            seattle XYZ     KC      14   
3   Microsoft       2355    null            null    null    null    4    

Vous pouvez test, jouez avec ceci en utilisant des exemples de données de votre question comme ci-dessous

#standardSQL
WITH `project.dataset.table` AS (
  SELECT 'Microsoft' company_name, 2355 phone, NULL email, NULL city, NULL address, NULL state UNION ALL
  SELECT 'Microsoft', 1234, NULL, 'seattle', 'XYZ', 'KC' UNION ALL
  SELECT 'Microsoft', 2355, 'any@example.com', NULL, NULL, NULL
), weights AS (
  SELECT 'phone' field, 4 weight UNION ALL
  SELECT 'email', 100 UNION ALL
  SELECT 'city', 2 UNION ALL
  SELECT 'address', 1 UNION ALL
  SELECT 'state', 7
)
SELECT 
  ANY_VALUE(t).*,
  SUM(weight) score
FROM `project.dataset.table` t
CROSS JOIN weights w 
WHERE REGEXP_EXTRACT(TO_JSON_STRING(t), CONCAT(r'', field, '":"?(.*?)"?[,}]')) != 'null'
GROUP BY TO_JSON_STRING(t)
ORDER BY score DESC

avec résultat

Row company_name    phone   email           city    address state    
1   Microsoft       2355    any@example.com null    null    null      

Comme vous pouvez le voir ici , le gagnant a moins d'attributs disponibles que les autres lignes car il a plus d'attribut "précieux"

Vous pouvez voir le score en utilisant ci-dessous

#standardSQL
WITH `project.dataset.table` AS (
  SELECT 'Microsoft' company_name, 2355 phone, NULL email, NULL city, NULL address, NULL state UNION ALL
  SELECT 'Microsoft', 1234, NULL, 'seattle', 'XYZ', 'KC' UNION ALL
  SELECT 'Microsoft', 2355, 'any@example.com', NULL, NULL, NULL
), weights AS (
  SELECT 'phone' field, 4 weight UNION ALL
  SELECT 'email', 100 UNION ALL
  SELECT 'city', 2 UNION ALL
  SELECT 'address', 1 UNION ALL
  SELECT 'state', 7
)
SELECT
  ARRAY_AGG(r ORDER BY score DESC LIMIT 1)[OFFSET(0)].*
FROM (
  SELECT 
    ANY_VALUE(t) r,
    SUM(weight) score
  FROM `project.dataset.table` t
  CROSS JOIN weights w 
  WHERE REGEXP_EXTRACT(TO_JSON_STRING(t), CONCAT(r'', field, '":"?(.*?)"?[,}]')) != 'null'
  GROUP BY TO_JSON_STRING(t)
)
GROUP BY r.company_name   

donc les scores sont p>

#standardSQL
WITH weights AS (
  SELECT 'phone' field, 4 weight UNION ALL
  SELECT 'email', 100 UNION ALL
  SELECT 'city', 2 UNION ALL
  SELECT 'address', 1 UNION ALL
  SELECT 'state', 7
)
SELECT
  ARRAY_AGG(r ORDER BY score DESC LIMIT 1)[OFFSET(0)].*
FROM (
  SELECT 
    ANY_VALUE(t) r,
    SUM(weight) score
  FROM `local-bastion-154121.Property_Dataset.pmDATA` t
  CROSS JOIN weights w 
  WHERE REGEXP_EXTRACT(TO_JSON_STRING(t), CONCAT(r'', field, '":"?(.*?)"?[,}]')) != 'null'
  GROUP BY TO_JSON_STRING(t)
)
GROUP BY r.company_name    


2 commentaires

Merci :) C'était d'une grande aide. Je voulais pondérer cet attribut, mais je n'ai jamais pensé que je pouvais aussi avoir une requête de cette façon.


sûr. revenez et votez pour la réponse lorsque vous avez suffisamment de réputation ici o)