Check alle échte Black Friday-deals Ook zo moe van nepaanbiedingen? Wij laten alleen échte deals zien

[MS SQL] waardes ophalen die niet in m'n range tabel zitten

Pagina: 1
Acties:

  • Russel88
  • Registratie: Juli 2009
  • Laatst online: 23:13
Hoi,

Ik zit met een query in m'n maag.
Het is meer, ik kan voor deze situatie geen query bedenken.

Ik heb een tabel waar o.a. 2 integer kolommen in staan. Daarin wordt een From To mechanisme gebruikt.
Nu wil ik alle getallen hebben tussen de 100 en de 1000 die niet in de From To range vallen.

Ik kan dit oplossen door een domme cursor te gebruiken, of gebruik te maken van temp tables.
Echter wil ik 1 query hebben die ik in een view kan gebruiken. Dus valt een cursor en temp table af. En volgens mij kan dat veel handiger met ingebouwde functies van MS Sql.

Ik weet alleen niet hoe :)
Kan iemand mij verder helpen hiermee?

Alvast bedankt

  • Exception
  • Registratie: Augustus 2006
  • Laatst online: 23-11 07:10
Kun je eens posten hoe die tabel eruit ziet? Want zoals ik het nu begrijp kun je dit met BETWEEN oplossen?

  • Russel88
  • Registratie: Juli 2009
  • Laatst online: 23:13
RangeTable(Van int, Tot int)
Met b.v. de volgende waardes:
100 - 200
201 - 368
370 - 600
601 - 888
890 - 1000

Resultaat van m'n query moet dus zijn:
369
889

  • Russel88
  • Registratie: Juli 2009
  • Laatst online: 23:13
Thanks.
Maar in de thread worden temp tables geadviseerd. Dit wil ik liever vermijden en hoopte ik dat MS SQL wat handige functies heeft die ik niet ken en me hierbij kan helpen.

  • NMe
  • Registratie: Februari 2004
  • Laatst online: 20-11 11:59

NMe

Quia Ego Sic Dico.

Lijkt me in elk geval erg sterk. SQL is vooral bedoeld om data op te halen die bestaat in een tabel en jij wil juist data ophalen die niet bestaat in een tabel, en als klap op de vuurpijl gaat het niet alleen om waardes in die tabel maar ook de waardes die tussen twee "arbitraire" velden liggen. Als daar iets in mogelijk is zonder een temp table zou me dat heel erg verbazen.

'E's fighting in there!' he stuttered, grabbing the captain's arm.
'All by himself?' said the captain.
'No, with everyone!' shouted Nobby, hopping from one foot to the other.


  • Russel88
  • Registratie: Juli 2009
  • Laatst online: 23:13
NMe schreef op vrijdag 15 maart 2013 @ 11:37:
Lijkt me in elk geval erg sterk. SQL is vooral bedoeld om data op te halen die bestaat in een tabel en jij wil juist data ophalen die niet bestaat in een tabel, en als klap op de vuurpijl gaat het niet alleen om waardes in die tabel maar ook de waardes die tussen twee "arbitraire" velden liggen. Als daar iets in mogelijk is zonder een temp table zou me dat heel erg verbazen.
Hier was ik al bang voor.
Bedankt in ieder geval voor de reacties.

[ Voor 3% gewijzigd door Russel88 op 15-03-2013 11:47 ]


  • nescafe
  • Registratie: Januari 2001
  • Laatst online: 23:06
Als je het direct in een view wilt gebruiken, zou je een (table valued) user defined function kunnen maken.

Afhankelijk van wat je verdere wensen zijn kun je die een hele range laten genereren en op basis van een outer join (joinconditie BETWEEN en wherestatement IS NULL) de missende getallen tevoorschijn halen.

* Barca zweert ook bij fixedsys... althans bij mIRC de rest is comic sans


Verwijderd

Russel88 schreef op vrijdag 15 maart 2013 @ 11:46:

Hier was ik al bang voor.
Bedankt in ieder geval voor de reacties.
Volgende vraag dan. Waarom heb je dit binnen een view nodig? Sowieso kun je dit niet als foreign key gebruiken, want zinloos, er zal nooit een link zijn tussen deze view en andere tabellen. Volgens mij kun je er op databaseniveau weinig mee en is dit veelal een presentatie-issue.

  • P_de_B
  • Registratie: Juli 2003
  • Niet online
SQL:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
--testtabel maken
CREATE TABLE Ranges (id int, van int, tot int)
INSERT INTO Ranges (id, van, tot) values (1, 0, 100)
INSERT INTO Ranges (id, van, tot) values (1, 100, 200)
INSERT INTO Ranges (id, van, tot) values (1, 201, 368)
INSERT INTO Ranges (id, van, tot) values (1, 370, 600)
INSERT INTO Ranges (id, van, tot) values (1, 601, 888)
INSERT INTO Ranges (id, van, tot) values (1, 890, 1000)


--we gebruiken een tabel Tally gevuld met alle nummers die je wilt checken
CREATE TABLE Tally (num int)

--vullen van de tabel
DECLARE @i int = 1
WHILE @i < 1000
BEGIN
    INSERT INTO Tally (num) values (@i)
    SET @i = @i + 1
END

--gebruik nu de tabel om de missende nummers te vinden
SELECT t.num 
FROM Tally t
LEFT OUTER Join Ranges R ON t.num BETWEEN r.van AND r.tot
WHERE r.id IS NULL


Kijk bijvoorbeeld eens hier voor meer info over 'Tally' tabellen :)

[ Voor 8% gewijzigd door P_de_B op 15-03-2013 11:55 ]

Oops! Google Chrome could not find www.rijks%20museum.nl


  • Russel88
  • Registratie: Juli 2009
  • Laatst online: 23:13
Bedankt voor alle antwoorden.
Ik heb een aantal ideeen samengevoegd.
Een table valued functie:
SQL:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
CREATE    FUNCTION DummyRangeValues (@from as int, @to as int)  
RETURNS @myTable table 
(
    Number int
)
AS  
Begin
    Declare @i int = @from
    
    While @i < @to
    Begin
        Insert into @myTable(Number)
        Values (@i)
        Set @i = @i + 1
    End

    Return
End; 


En daarna m'n view als volgt geschreven:
SQL:
1
2
3
4
Select d.Number
From DummyRangeValues(100, 999) d
Left outer Join Range r on d.Number Between r.FromVal AND r.ToVal
Where r.ID is null

  • P_de_B
  • Registratie: Juli 2003
  • Niet online
Waarom maak je niet een echte tabel DummyRangesValues? Nu wordt iedere keer die tabel opnieuw opgebouwd.

Oops! Google Chrome could not find www.rijks%20museum.nl


  • Russel88
  • Registratie: Juli 2009
  • Laatst online: 23:13
P_de_B schreef op vrijdag 15 maart 2013 @ 12:49:
Waarom maak je niet een echte tabel DummyRangesValues? Nu wordt iedere keer die tabel opnieuw opgebouwd.
Flexibiliteit.
Willen ze in de toekomst een extra controle van 100 tm 500, dan hoef ik geen nieuwe tabel aan te maken.

  • P_de_B
  • Registratie: Juli 2003
  • Niet online
Dan zou ik nog die tabel aanmaken en in de view where d.Number BETWEEN 100 AND 999 gebruiken. Het is denk ik zonde om die tabel steeds opnieuw aan te maken, maar dat is ook afhankelijk van hoe vaak deze view wordt aangeroepen. Als dat 2x per dag is, zit het denk ik niemand in de weg. Iedere minuut wordt al vervelender.

Oops! Google Chrome could not find www.rijks%20museum.nl


  • KopjeThee
  • Registratie: Maart 2005
  • Niet online
Russel88 schreef op vrijdag 15 maart 2013 @ 11:20:
RangeTable(Van int, Tot int)
Met b.v. de volgende waardes:
100 - 200
201 - 368
370 - 600
601 - 888
890 - 1000

Resultaat van m'n query moet dus zijn:
369
889
Geen idee of dit werkt, niet uitgeprobeerd en ik ben niet echt een SQL kenner. Maar die tabel met zichzelf joinen. Dan natuurlijk proberen aan de rechterkant (r) telkens de rij te zetten die direct volgt op de range van de linkerkant (l). Zodat je de "tot" van de linkerkant (l) kunt vergelijken met de "van" van de rechterkant (r), en daar ontbrekende ranges uit kunt maken.
SQL:
1
2
3
4
5
6
7
8
create view OntbrekendeRanges as
select
  l.tot + 1 as ontbrekend_van,
  r.van - 1 as ontbrekend_tot
from RangeTable as l, RangeTable as r
where l.tot - r.van > 1
group by l.tot
having l.tot - r.van = min(l.tot - r.van)

[ Voor 3% gewijzigd door KopjeThee op 15-03-2013 21:18 ]


  • RobIII
  • Registratie: December 2001
  • Niet online

RobIII

Admin Devschuur®

^ Romeinse Ⅲ ja!

(overleden)
Ik zou dit hebben gedaan (gebaseerd op P_de_B's Range testtabel, regel 1-8 dus):

SQL:
1
2
3
4
5
6
7
8
9
10
11
12
Declare @start int, @end int
Select @start=min(van), @end=max(tot) from ranges;
With NumberSequence( Number ) as (
    Select @start as Number union all
    Select Number + 1
    From NumberSequence
    Where Number < @end
)
Select Number
From NumberSequence
Where Not exists(Select 1 From Ranges Where Number Between van and tot)
Option (MaxRecursion 0)

369
889

:Y)
Deze gaat uit van de hoogste "tot" en de laagste "van" (regel 2) om te bepalen waartussen de ontbrekende getallen gezocht moeten worden; je kunt natuurlijk ook gewoon @start en @end 'hardcoden'.
Vervolgens wordt een sequence (met 'interval' van 1) gegenereerd en daarna wordt met een not exists (leest 't makkelijkst) gekeken welke getallen ontbreken.

Geen cursors, geen temp/tally tables, geen while lussen. Maar hou er wel rekening mee dat een 'tally table' bij grote(re) aantallen dan nu (0-1000) waarschijnlijk beter gaan performen.

Regel 10/11 kun je ook schrijven als:
SQL:
1
2
Left outer join Ranges on Number between van and tot
Where id is null

Zie hier voor meer info.

[ Voor 52% gewijzigd door RobIII op 15-03-2013 22:10 ]

There are only two hard problems in distributed systems: 2. Exactly-once delivery 1. Guaranteed order of messages 2. Exactly-once delivery.

Je eigen tweaker.me redirect

Over mij


  • pedorus
  • Registratie: Januari 2008
  • Niet online
Interessant, maar vooralsnog wint de tally table:
I can’t really think of a situation in which I’ll use the recursive CTE for this specific issue.

Vitamine D tekorten in Nederland | Dodelijk coronaforum gesloten


  • DamadmOO
  • Registratie: Maart 2005
  • Laatst online: 21-11 19:40
De tally table zal altijd winnen. De enige CTE die er dicht bij in de buurt komt is die van Itzik:
SQL:
1
2
3
4
5
6
7
8
9
10
11
  WITH E00(N) AS (SELECT 1 UNION ALL SELECT 1),
        E02(N) AS (SELECT 1 FROM E00 a, E00 b),
        E04(N) AS (SELECT 1 FROM E02 a, E02 b),
        E08(N) AS (SELECT 1 FROM E04 a, E04 b),
        E16(N) AS (SELECT 1 FROM E08 a, E08 b),
        E32(N) AS (SELECT 1 FROM E16 a, E16 b),
   cteTally(N) AS (SELECT ROW_NUMBER() OVER (ORDER BY N) FROM E32)
 SELECT N
  FROM cteTally
  WHERE N <= 1000000;
GO


Mijn persoonlijk voorkeur is om gewoon een Tally tabel te hebben. Maak deze gewoon groot genoeg zodat deze in de toekomst niet meteen te klein is. Zoveel opslag kost het namelijk niet. Er zijn erg veel problemen die met behulp van een Tally tabel een stuk makkelijker opgelost kunnen worden, ook al is er met de komst van SQL 2012 en window functions ook een boel mogelijk zonder extra tabel.
Pagina: 1