Avatar billede tblaster Nybegynder
31. juli 2008 - 15:58 Der er 11 kommentarer og
2 løsninger

Søge felt med komma-liste igennem for værdier i anden kommaliste

Jeg står med en liste af værdier 1,2,3,4,5 som jeg gerne vil søge en ms sql database igennem for og finde de poster der passer til en af værdierne i listen. Normalt ville jeg gøre dette vha. følgende:

SELECT * From Tabel Where Felt in (1,2,3,4,5) eller ('1','2',..) for varchar felter.

Problemet er at mit felt i databasen er af typen varchar og indeholder en kommaseperaret liste af værdier, eks. er følgende gyldige informationer i feltet:
1
,1,
,1,2,

Så når jeg forespørger databasen for poster der er i følgende liste, 1,2,3,4,5, så skal jeg få alle 3 ovenstående poster.

Hvis jeg spørger på ('1','2','3','4','5') så får jeg kun den første post og spørger jeg på (1,2,3,4,5) får jeg følgende fejl:

Conversion failed when converting the varchar value ',4,' to data type int.

Løsningen skal kunne klares i en sql statement og ikke efter udtrækket af posterne!

Håber I kan hjælpe.
Avatar billede thesurfer Nybegynder
31. juli 2008 - 19:06 #1
Det virker som om at det mere er LIKE du skal bruge, i stedet for IN.

Eksempel:

Like '%ug%': Finder "hugo", da "ug" indgår i hugo
Like 'hu%': Finder "hugo" og "hus", da begge disse ord starter med "hu"
Like '%r': Finder ord som f.eks. "for" og "poster", da disse ender med "r"
Avatar billede thesurfer Nybegynder
31. juli 2008 - 19:08 #2
Med andre ord:

%-tegnet er det wildcard, svarende til f.eks. "*" andre steder/i programmer.
Avatar billede thesurfer Nybegynder
31. juli 2008 - 19:09 #3
Det skal lige siges, at IN-delen svarer til at du f.eks gør sådan her:

where felt = "1" or felt = "2" or felt = "3" ...osv..

Dvs., værdierne skal passe sammen 100%.. hvilket ikke er helt hvad du søger..
Avatar billede kjulius Novice
31. juli 2008 - 23:05 #4
En kommasepareret liste i et felt kan du ikke bruge til en skiiii... - i databasesammenhæng. Det er et misfoster, som du burde skrotte pronto. Sådanne værdier bør placeres i en selvstændig tabel, hvor hver række repræsenterer en værdi. Hvis de så senere skal præsenteres som en kommasepareret liste, kan det gøres i applikationslaget (f.eks. PHP eller lign.).
Avatar billede thesurfer Nybegynder
31. juli 2008 - 23:42 #5
Hvis man har flere lister, med f.eks.
,1,2,3,
,3,4,5,

Og man ville finde 3'erne, skal man ikke søge på "3", men på ",3," om en enkel værdi..
Avatar billede tblaster Nybegynder
31. juli 2008 - 23:55 #6
kjulius:
det er jeg med på men det kan ikke lade sig gøre i dette tilfælde

thesurfer:
det jeg søger er din forklaring af IN-delen med at den søger med or kommandoen. Men en løsning som like '%,1,%' or ... '%,1,2,' vil være en for stor løsning da selv med 10 værdier skal der laves en masse or udtræk.
Avatar billede kjulius Novice
01. august 2008 - 01:06 #7
OK, disse idéer er måske lidt langt ude...

1) Man kunne tænke sig, at du registrerede en trigger på tabellen, som så vedligeholdt en "alm." tabel, som indeholdt dine kommaseparerede værdier. Hver gang rækken ændres kaldes trigger-rutinen. Denne tjekker, om feltets værdier findes i "skyggetabellen". Hvis ikke sørger den for at synkronisere dem.

På den måde vil du kunne bruge "skyggetabellen" til dine opslag.


2) En anden mulig måde at løse problemet på, er at lave en UDF, som f.eks. returnerer antallet af værdier i to kommaseparerede lister, som er ens. Så kunne du f.eks. lave en søgning som

SELECT * FROM tabel WHERE CMPLISTS(felt1, '1,3,7,9') > 0

NB! Funktionen CMPLIST ville så være UDF'en (User Defined Function).

Selve funktionen kan enten programmeres i T-SQL eller i et .NET sprog som f.eks. C# eller VB.NET og registreres vha. CREATE FUNCTION.

Tja, det var lidt at tænke over... :-)
Avatar billede thesurfer Nybegynder
01. august 2008 - 01:15 #8
Typisk brug af IN er følgende:

Delete from MinTabel where id IN ( select id from MinTabel where aktiv = false )

Der sker følgende:
- Sætningen "select id from MinTabel where aktiv = false" returnerer ID'erne på de poster, hvor feltet "aktiv" er lige false, fra tabellen MinTabel.

- Sætningen "Delete from MinTabel where id IN(...)" sletter poster hvor ID'erne i tabellen MinTabel passer med ID'er (komma-separaret integer/tal liste) der returneres af SELECT-sætningen.

Dvs., hvis SELECT-sætningen returnerer 1,2,3 så slettes posterne med ID 1, ID 2 og ID 3. Den vil IKKE slette 11 hvis den findes, da 11 IKKE er lig 1.
I denne situation ville det derfor være dumt at bruge LIKE i stedet for IN.

Der er forskel på "er lig" (som betyder "er 100% identisk med") og "indeholder".

Brug:
- IN: "er lig"
- LIKE: "indeholder"


Angende min forklaring med IN og OR:

Det er "lige meget" om du bruger "WHERE felt IN (1,2,3)" eller "WHERE felt = 1 Or felt = 2 OR felt = 3".. begge sætninger giver det samme resultat:

De poster hvor indeholdet af felterne ("felt") indeholder nøjagtigt (dvs. 100% identisk) en af disse værdier:

1
2
3

Hvis der f.eks. står 11, eller 12, eller 13 (eller andre kombination tallene 1, 2 og/eller 3), returneres disse IKKE.
Avatar billede thesurfer Nybegynder
01. august 2008 - 01:21 #9
Forstil dig en telefonbog med navnene:

Hans Hansen
Hans H Hansen
Jens Jensen
Jens J Jensen

SQL: WHERE navn IN ('Hans Hansen','Jens J Jensen')
Svarer til: WHERE navn = 'Hans Hansen' OR navn = 'Jens J Jensen'
Resultat: Hans Hansen, Jens J Jensen

SQL: WHERE navn IN ('J'):
Svarer til: WHERE navn = 'J'
Resultat: ingenting da der ikke er nogen poster, der udelukkende består af bogstavet "J", og ikke andet.

SQL: WHERE navn LIKE '%J%':
Resultat: Jens Jensen, Jens J Jensen

SQL: WHERE navn LIKE '%ens%'
Resultat: Jens Jensen, Jens J Jensen
Avatar billede thesurfer Nybegynder
01. august 2008 - 01:55 #10
Jeg kommer lige i tanke om noget.. kjulius var sådan set ind på det i 31/07-2008 23:05:23.

Hvis dine værdier (1,2,3) repræsenterer egenskaber ved et objekt, f.eks. i form af checkbokse, der indikerer hvilke attributter objektet har, så er der en bedre måde at gøre det på (det kjulius forslog i 31/07-2008 23:05:23, som jeg har forstået det)..

Eksempel:

Tabel: attributter

ID: 22
Attribut: sidespejl
AID: 1

ID: 35
Attribut: pejs
AID: 2

ID: 45
Attribut: håndbremse
AID: 3

ID: 76
Attribut: køleskab
AID: 4

Hvis objektet er en bil, har objektet måske en eller flere af attributterne: 1,3
Hvis objektet er et hus, har objektet måske en eller flere af attributterne: 2,4

Da biler normalt hverken har pejs eller køleskab, har objektet hverken attributten 2 eller 4.
Og da et hus normalt hverken har sidespejl eller håndbremse, har objektet hverken attributten 1 eller 3.


Tabel: objekter

ID: 8
Type: Bil
Model: Ford Mustang
Attribut: 1

ID: 27
Type: Lejlighed
Alder: Ny
Attribut: 2

ID: 98
Type: Bil
Model: Toyota Carina
Attribut: 3

ID: 454
Type: Villa
Alder: Gammel
Attribut: 4


Hvis du kender AID (Attribut ID) og vil se hvilke biler der findes, kan du gøre sådan her:
SELECT model FROM objekter WHERE attribut IN (1,3)
Resultat: Ford, Toyota

Hvis du bare ved at det er en Ford, og vil have AID, kan gør du sådan her:
SELECT aid FROM objekter WHERE model LIKE 'Ford%'
Resultat: 1


Som du sikker har lagt mærke til, betyder det at hver bil kan have op til 2 poster (hvis vi holder os til sidespejl / pejs / håndbremse / køleskab egenskaberne) i databasen.
Men jeg tror at have 2 poster er mere effektivt, end at skulle parse (gennemlæse / gennemsøge) indeholdet af en enkel post..
Avatar billede tblaster Nybegynder
12. august 2008 - 12:43 #11
Tak for jeres input. Post et svar, så skal I få lov at dele pointene.
Avatar billede thesurfer Nybegynder
13. august 2008 - 20:57 #12
Svar.
Avatar billede kjulius Novice
14. august 2008 - 19:23 #13
Tak. Der kan måske falde et par enkelte point af, efter at du har belønnet thesurfer for indsatsen og ihærdigheden. :-)
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
Computerworld tilbyder specialiserede kurser i database-management

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester