Requète impossible à faire simplement?

Requète impossible à faire simplement? - SQL/NoSQL - Programmation

Marsh Posté le 28-11-2003 à 14:35:00    

Supposons les tables triviales A et B suivantes:
 
A
_
1
1
1
2
2
 
B
_
1
2
 
Maintenant, je voudrais arriver à retirer de A les élément de B le nombre de fois qu'ils sont présents dans B, ce qui me donnerait au final
 
A
_
1
1
2
 
Pour obtenir ce résultat dans une sélection, pas de problème, ca passe sans problème avec un except, mais je ne vois pas le moyen simple de le faire pour un delete. Et je ne peux pas me permettre de faire une copie de la table que je renommerais par la suite.
 
quelqu'un aurait-il une idée? En PgSQL, et si possible en restant dans le SQL standard (mais c'est pas obligé).

Reply

Marsh Posté le 28-11-2003 à 14:35:00   

Reply

Marsh Posté le 28-11-2003 à 15:43:28    

Est-ce que tu peut ajouter (temporairement) des colonnes à A et à B ?


---------------
Laissez l'Etat dans les toilettes où vous l'avez trouvé.
Reply

Marsh Posté le 28-11-2003 à 15:46:26    

J'y ai pensé. rajouter une colonne avec un compteur mais c'est assez lourd. Je cherchais, si possible une solution plus légère.

Reply

Marsh Posté le 28-11-2003 à 15:49:29    

Idée :
 
Je nome X, la colonne qui contient les données dont tu parles.
 
1- Ajouter un champ ID dans A et dans B.
2- Dans A, l'ID vas de 1 à N c'est en gros un N° d'enregistrement
3- Dans B, update B set ID = (select A.ID from A where A.X = B.X and A.ID=min(A.ID) )
4- delete A where ID in ( select ID from B )
5- Supprimer les champs ID dans A et B


---------------
Laissez l'Etat dans les toilettes où vous l'avez trouvé.
Reply

Marsh Posté le 28-11-2003 à 16:25:36    

C'est merdique ton truc.
 
Est-ce que ta base de données permet de bosser avec le RowID ?
 
Si oui, alors pas besoin d'ajouter un identifiant, il y est déjà, c'est le rowid.

Reply

Marsh Posté le 28-11-2003 à 16:28:30    

Y fait comme y veux hein.
Mais pour son problème, ben je vois pas grand chose d'autre (dans le principe général) s'il ne peut pas recopier dans une autre table.


---------------
Laissez l'Etat dans les toilettes où vous l'avez trouvé.
Reply

Marsh Posté le 28-11-2003 à 16:28:49    

Sinon, je vois pas comment c'est possible en SQL Standard, à moins de passer par du PL/SQL ou T-SQL.
 
Je verrais un truc bourrin comme ça :
 

delete A where rowid in (select top (select count(col) from B group by B.col) rowid
from A
where A.col = B.col)


 
Mais je doute que cette requête marche (j'ai pas de sql server sous la main, et avec oracle y'a pas de "top" )

Reply

Marsh Posté le 28-11-2003 à 16:33:24    

c'est tout faux mon truc. Mais y'a de l'idée. Chuis en train de voir comment la refaire sous Oracle

Reply

Marsh Posté le 28-11-2003 à 16:38:51    

Mmm... En fait mon truc est pas possible, il faudrait pouvoir faire un group by sur le top, et c'est pas possible à ma connaissance...

Reply

Marsh Posté le 28-11-2003 à 16:48:00    

Je l'ai :
 

Code :
  1. delete from A
  2. where
  3. rowid in
  4.  select
  5.   x_row
  6.  from
  7.  (
  8.   select
  9.    a.col,
  10.    min( A.rowid ) x_row
  11.   from
  12.    A,
  13.    B
  14.   where
  15.    A.col = B.col
  16.   group by
  17.    a.col
  18.  )
  19. )


---------------
Laissez l'Etat dans les toilettes où vous l'avez trouvé.
Reply

Marsh Posté le 28-11-2003 à 16:48:00   

Reply

Marsh Posté le 28-11-2003 à 16:49:28    

M'enfin c'est pour Oracle, (testé et approuvé ), reste à l'adapter à postgres.
Y'a des rowid dans postgres ?


---------------
Laissez l'Etat dans les toilettes où vous l'avez trouvé.
Reply

Marsh Posté le 28-11-2003 à 16:51:23    

elle est bizarre ta requête.  
 


     select
      a.col,
      min( A.rowid ) x_row
     from
      A,
      B
     where
      A.col = B.col
     group by
      a.col


 
Ca fait quoi au juste ça ? (peut pas trop jouer sur le serveur ici, c'est la base de l'ERP et ça ferait chier les gens si je virait des commandes et des clients pour tester :D)

Reply

Marsh Posté le 28-11-2003 à 16:52:24    

ok, merci pour vos efforts...mais:
 
- pour le moment, je ne connais aucun moyen d'accéder aux rowid dans postgres. J'ai beau chercher dans la doc, je ne vois rien (j'ai essayé rowid et row_id sans sucès) :/
 
- la solution de Mara's dad fonctionnera effectivement si je n'ai que des valeurs uniques dans B. Mon problème, que j'ai oulié de précisé (mea culpa) c'est que je pourrais très bien avoir un B comme ça:
B
_
1
1
2
 
voila voila

Reply

Marsh Posté le 28-11-2003 à 17:01:55    

MagicBuzz :
 
quand je fais
 
where toto in (...)
 
ce qu'il y a dans (...) ne doit retourner qu'un seul champs.
 
Or pour faire la sélection de ce qu'on veux, il faut faire :
 
select un_champs, min(rowid), from table group by un_champs.
 
ce qui retourne 2 champs !
 
Donc je donne un alias à min(rowid) et j'encapsule le tout dans une autre requête :
 
select x_row from (...)  
 
C'est une astuce que j'ai déjà utilisé, mais çà fait au moins 3 niveaux d'imbrication !
 
gizmo:
T'est chiant  :D


---------------
Laissez l'Etat dans les toilettes où vous l'avez trouvé.
Reply

Marsh Posté le 28-11-2003 à 17:03:39    

je sais [:ddr555]

Reply

Marsh Posté le 28-11-2003 à 17:04:05    

gizmo :
T'as pas un identifiant unique dans A pour remplacer le rowid ?
 
Pour le reste, je cherche...


---------------
Laissez l'Etat dans les toilettes où vous l'avez trouvé.
Reply

Marsh Posté le 28-11-2003 à 17:07:49    

Mara's dad a écrit :

MagicBuzz :
 
quand je fais
 
where toto in (...)
 
ce qu'il y a dans (...) ne doit retourner qu'un seul champs.
 
Or pour faire la sélection de ce qu'on veux, il faut faire :
 
select un_champs, min(rowid), from table group by un_champs.
 
ce qui retourne 2 champs !
 
Donc je donne un alias à min(rowid) et j'encapsule le tout dans une autre requête :
 
select x_row from (...)  
 
C'est une astuce que j'ai déjà utilisé, mais çà fait au moins 3 niveaux d'imbrication !
 
gizmo:
T'est chiant  :D  


ça j'avais bien compris ;)
c'est le premier truc que j'ai corrigé dans ma requête quand j'ai commencé à jouer avec :D
 
mais je vois pas où tu "retirer de A les élément de B le nombre de fois qu'ils sont présents dans B"

Reply

Marsh Posté le 28-11-2003 à 17:08:31    

ha ! je crois que je viens d'avoir une illumination.
 
nan, ct pas une apparition de la vierge, c'est juste que je viens de tilter. j'ai compris la requête  ;)
 
chapeau :jap:

Reply

Marsh Posté le 28-11-2003 à 17:12:37    

L'identifiant de record dans postgres, c'est OID !
 
http://www.postgresql.org/docs/7.4 [...] lumns.html


---------------
Laissez l'Etat dans les toilettes où vous l'avez trouvé.
Reply

Marsh Posté le 28-11-2003 à 18:03:36    

Appelez moi DIEU !
 
delete from "A" where "A".OID in ( select "A".OID from "A" where "A".col || '_' || ( select count(*) from "A" as a1 where a1.OID <= "A".OID AND a1.col="A".col ) in ( select "B".cal || '_' || ( select count(*) from "B" as b1 where b1.OID <= "B".OID AND b1.col="B".col ) from "B" ) );
 
 :sol:  :sol:  :sol:


Message édité par Mara's dad le 28-11-2003 à 22:59:43

---------------
Laissez l'Etat dans les toilettes où vous l'avez trouvé.
Reply

Marsh Posté le 28-11-2003 à 18:05:33    

[:prosterne][:prosterne][:prosterne]
[:prosterne][:prosterne][:prosterne]
[:prosterne][:prosterne][:prosterne]
 
:jap::jap::jap:
:jap::jap::jap:
:jap::jap::jap:

Reply

Marsh Posté le 28-11-2003 à 18:09:42    

J'ai rarement vu un truc aussi capilotracté :lol:


---------------
Laissez l'Etat dans les toilettes où vous l'avez trouvé.
Reply

Marsh Posté le 28-11-2003 à 18:12:07    

Mara's dad a écrit :

Appelez moi DIEUX !
 
delete from "A" where "A".OID in ( select "A".OID from "A" where "A".col || '_' || ( select count(*) from "A" as a1 where a1.OID <= "A".OID AND a1.col="A".col ) in ( select "B".cal || '_' || ( select count(*) from "B" as b1 where b1.OID <= "B".OID AND b1.col="B".col ) from "B" ) );
 
 :sol:  :sol:  :sol:  



note pour plus tard : Mara's dad sait faire des requêtes incompréhensible et qui marche
:whistle:


---------------
from here and there -- \o__________________________________ -- la révolution de la terre, en silence
Reply

Marsh Posté le 28-11-2003 à 18:13:57    

simogeo a écrit :



note pour plus tard : Mara's dad sait faire des requêtes incompréhensible et qui marche
:whistle:  


 
Comment çà incompréhensible ?


---------------
Laissez l'Etat dans les toilettes où vous l'avez trouvé.
Reply

Marsh Posté le 28-11-2003 à 18:17:21    

Mara's dad a écrit :


 
Comment çà incompréhensible ?


dans le sens ou j'ai rien capté  :D  .... j'ai pas essayé de capter non plus  ;)  ... mais rien que la syntaxe m'effraie [:totoz]
 
bien joué, quoi [:bien]
 
edit : viens de regarder, et ca n'a pas l'air si compliqué que ca en fait mais bon, c'est bien quand même  :o  :D


Message édité par simogeo le 28-11-2003 à 18:18:35

---------------
from here and there -- \o__________________________________ -- la révolution de la terre, en silence
Reply

Marsh Posté le 28-11-2003 à 18:25:31    

OID, c'est un identifiant numérique unique de postgres, donc :
 
select col, ( count(*) from A as a1 where a1.OID <= A.OID AND a1.col=A.col ) FROM A
Donne :
1 1
1 2
1 3
2 1
2 2
 
En clair, pour chaque valeur de col, je compte combien de records de la table on la même valeur de col et un OID plus petit.
 
Je fait pareil pour B :
1 1
1 2
2 1
 
Ensuite je concatène les champs avec un _ entre les deux (pour chaque table) :
pour A:
1_1
1_2
1_3
2_1
2_2
 
Pour B:
1_1
1_2
2_1
 
On a alors la liste des pseudo valeurs à supprimer, reste à tout mettre ensemble :
 
delete from A where OID in ( select OID from A where CONCATENATION_DE_COL_ET_DU_COMPTEUR_DE_A in ( SELECT CONCATENATION_DE_COL_ET_DU_COMPTEUR_DE_B from B ) );
 
 
Faut juste prendre le problème dans le bon sens :D


---------------
Laissez l'Etat dans les toilettes où vous l'avez trouvé.
Reply

Marsh Posté le 28-11-2003 à 18:35:59    


 
Bah comme ça moi j'apprends des trucs  :)

Reply

Marsh Posté le 28-11-2003 à 18:37:09    

et si tu faisais la selection dans ton appli, "betement" ? [:spamafote]


---------------
Hey toi, tu veux acheter des minifigurines Lego, non ?
Reply

Marsh Posté le 28-11-2003 à 22:36:21    

the real moins moins a écrit :

et si tu faisais la selection dans ton appli, "betement" ? [:spamafote]


gni?

Reply

Marsh Posté le 28-11-2003 à 23:09:56    

the real moins moins a écrit :

et si tu faisais la selection dans ton appli, "betement" ? [:spamafote]


[:newidk]


---------------
from here and there -- \o__________________________________ -- la révolution de la terre, en silence
Reply

Marsh Posté le 28-11-2003 à 23:10:10    

il veut dire dans le programme qui appelle la requête sql plutôt que directement dans la requête

Reply

Marsh Posté le 28-11-2003 à 23:12:09    

Dans le prog, pourquoi pas !
 
T'as un algo simple pour faire çà MagicBuzz ?
 
Plus simple qu'une requête qui fait tout en une fois ?


---------------
Laissez l'Etat dans les toilettes où vous l'avez trouvé.
Reply

Marsh Posté le 28-11-2003 à 23:21:07    

ah! ok. Bah non, ça ne m'est pas possible. le programme qui demande la suppression ne travaille pas directement sur la DB mais au travers d'un wrapper, le schema de la DB étant censé pourvoir bouger dans le temps sans que l'appli n'aie à être remodifiée.

Reply

Marsh Posté le 28-11-2003 à 23:51:14    

Mara's dad a écrit :

Dans le prog, pourquoi pas !
 
T'as un algo simple pour faire çà MagicBuzz ?
 
Plus simple qu'une requête qui fait tout en une fois ?


y'a toujours le problème du rowid.
 
sans le rowid, je vois pas comment faire...
 
sinon, c'est simple en prog...
 
"select distinct A from T1"
while (canRead)
{
    "select count(A) from T2 where A = " + sqlA
    "delete T1 where rowID in (select top " + sqB + " from T1 where A = " + sqA + " )"
    moveNext
}

Reply

Marsh Posté le 28-11-2003 à 23:57:22    

T'as pas tou lu toi !
 
En postgres, y'a le OID qui fait la même chose que le rowid.
 
J'ai rien capté à ton algo...
En quoi il est plus simple que ma requête magique ?
 
Et puis faire des delete dans une boucle sur la même table, c'est jamais très safe . . .


---------------
Laissez l'Etat dans les toilettes où vous l'avez trouvé.
Reply

Marsh Posté le 29-11-2003 à 01:27:18    

1) en quoi j'ai pas tout lu ? je retire bien de A les éléments de B le nombre de fois qu'ils sont présents dans B :heink:
 
2) j'avais pas fait gaffe à ce post en effet.
 
3) il est pas plus compliqué que ta requête. j'ai jamais dit qu'il était plus simple, il est par contre plus trivial.
 
4) je vois pas en quoi c'est gênant de faire un delete dans une boucle...

Reply

Marsh Posté le 29-11-2003 à 10:06:51    

1,2- Je dis que t'as pas tout lu quand tu parles du problème du rowid :D
En postgres, y'a OID qui remplace.
 
3- Je viens de comprendre comment tu fait ton delete. OK, sauf que en postgres, c'est pas top, mais LIMIT.
 
4- Les deletes dans une boucle (sur la table elle même, et seulement dans ce cas) poser des problèmes avec certains SGBD.
 
---------------------------------------
 
Et puis merde, je suis désapointé parce-que tu t'es pas extasié devant ma super requête super géniale et tout :o


Message édité par Mara's dad le 29-11-2003 à 10:12:36

---------------
Laissez l'Etat dans les toilettes où vous l'avez trouvé.
Reply

Marsh Posté le 01-12-2003 à 00:59:30    

Mara's dad a écrit :

1,2- Je dis que t'as pas tout lu quand tu parles du problème du rowid :D
En postgres, y'a OID qui remplace.
 
3- Je viens de comprendre comment tu fait ton delete. OK, sauf que en postgres, c'est pas top, mais LIMIT.
 
4- Les deletes dans une boucle (sur la table elle même, et seulement dans ce cas) poser des problèmes avec certains SGBD.
 
---------------------------------------
 
Et puis merde, je suis désapointé parce-que tu t'es pas extasié devant ma super requête super géniale et tout :o


4) bah à priori, si tu fait une transaction pour le tout, du devrait pouvoir pallier aux éventuels problèmes de lock engendrés pas une série de delete de suite (seule problème éventuel que je vois)
 
-----------
 
Sisi, elle est très jolie ta requête, un peu mac giver sur les bords, mais tout à fait bien :D

Reply

Marsh Posté le    

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed