Cześć,
czy byłby mi ktoś w stanie pomóc napisać funkcję która po podaniu dwóch argumentów wyświetli mi pierwotne wartości z pewnego przedziału. Najprościej będzie wytłumaczyć to na przykładzie, otóż:
Podająć wartości z kolumny ID2,LP2 (1)
Chciałbym uzyskać wynik wartości kolumn ID1,LP1(1). Wartości w kolumnach ID1 i ID2 są zawsze unikatowe, tylko lp może wystąpić kilka razy.
Wiem że trzeba do tego użyć pętli jednak nie do końca mi to wychodzi. Byłym wdzięczy za pomoc
A dlaczego akurat chcesz uzyskać 1 rekord?
Panczo napisał(a):
A dlaczego akurat chcesz uzyskać 1 rekord?
Ponieważ specyfika tych danych wymaga pokazania pierwotnego LP,ID. Przykładowo ID to ID adresu a LP to numer paczki w spisie (jak widać zmienny). Chcę wiedzieć jaki jest pierwotny adres mojej paczki oraz numer na pierwszym spisie LP. Gdy ID1 i LP1 nie ma sie już do czego odwołać niżej to jest mój wynik.
Za ChRL nie rozumiem opisu słownego (ze ścisłością jak programista rozwiązujący problem). Za nic nie rozumiem, co oznaczają czerwone prostokąty, jaka to jest zależność
a) nie dajesz kodu, który próbujesz (tytuł mówi o funkcji)
b) najstarsi Indianie nie wiedzą (ale przypuszczają) że jest jakiś spory problem w projekcie bazy
c) pozyskanie jednego rekordu w MS-SQL możesz zrobić z TOP 1, ewentualnie sortując DESC - choc za cholerę nie rozumiem, o co ci chodzi
d) używasz nagle jakiś nazw z domeny (adres, spis) nigdy tego nie definiując
ZrobieDobrze napisał(a):
Za ChRL nie rozumiem opisu słownego (ze ścisłością jak programista rozwiązujący problem). Za nic nie rozumiem, co oznaczają czerwone prostokąty, jaka to jest zależność
a) nie dajesz kodu, który próbujesz (tytuł mówi o funkcji)
b) najstarsi Indianie nie wiedzą (ale przypuszczają) że jest jakiś spory problem w projekcie bazy
c) pozyskanie jednego rekordu w MS-SQL możesz zrobić z TOP 1, ewentualnie sortując DESC - choc za cholerę nie rozumiem, o co ci chodzi
d) używasz nagle jakiś nazw z domeny (adres, spis) nigdy tego nie definiując
Dobrze, no może nie wyjaśniłem tego w dobry sposób(jest to mój pierwszy post więc proszę o wyrozumiałość). Zależność jest taka że Adres1 i LP1 to adresy pierwotny paczki i jej lp. Jeżeli paczka przemieszcza się do innego adresu mamy wpis w Adres2 i LP2. Czyli w pierwszym wierszu z Adresu1 paczka o numerze 1 (LP1), przechodzi na Adres2 i dostaje nr. 2(LP2). Jeżeli z Adresu2 paczka idzie dalej to pojawia się nowy wiersz i tak dalej. Adresy zawszę są unikatowe czyli mamy powiązanie (adres,lp) 100,1 -> 200,2 -> 300,3 -> 500,5 -> 800,8. Podając ostatnie wartości czyli 800,8, chciałbym wiedzieć skąd moja paczka wystartowała.
Prawdopodobnie tak jak kolega mówi baza jest źle skonstruowana, jednakże działam na tym co mam. Co do kodu, niestety jak już wspomniałem nie jestem wstanie go zrobić dlatego napisałem z prośba o pomoc. Co do funkcji to właśnie ona przyszła mi do głowy, ponieważ chciałbym podawac dwa parametry. Jeżeli nie da sie tego zrobić to trudno. Jest to oczywiście przykład dla zobrazowania problemu, poniżej wklejam mojego inserta.
Create table dbo.paczki (ADRES1 INT, LP1 INT, ADRES2 INT, LP2 INT)
INSERT INTO DBO.paczki (ADRES1 , LP1 , ADRES2 , LP2 )
VALUES (100,1,200,2)
,(200,2,300,3)
,(300,3,500,5)
,(500,5,800,8)
Coś mi się wydaje, że nie zwracasz nam wszystkich pól z tabeli, bo mozna założyć że "pierwszym rekordem" jest ten który nie ma swojej pary w adres i lp2.
Ale brakuje rozróżnienia czego dotyczy przesyłka:
select *
from paczki s
where not exists(select * from paczki p where p.adres2=s.adres1 and p.lp2=s.lp1)
Powiedzmy że masz kolumnę id z wyróżnikiem paczki wtedy można rozbudować to tak:
select *
from paczki s
where
id in (select id from paczki where adres2=800 and lp2=8)
and not exists(select * from paczki p where p.adres2=s.adres1 and p.lp2=s.lp1)
Panczo napisał(a):
Coś mi się wydaje, że nie zwracasz nam wszystkich pól z tabeli, bo mozna założyć że "pierwszym rekordem" jest ten który nie ma swojej pary w adres i lp2.
Ale brakuje rozróżnienia czego dotyczy przesyłka:select * from paczki s where not exists(select * from paczki p where p.adres2=s.adres1 and p.lp2=s.lp1)
Powiedzmy że masz kolumnę id z wyróżnikiem paczki wtedy można rozbudować to tak:
select * from paczki s where id in (select id from paczki where adres2=800 and lp2=8) and not exists(select * from paczki p where p.adres2=s.adres1 and p.lp2=s.lp1)
Udało mi się to osiągnąć jednak w dość nietypowy sposób bo funkcją skalarną.
alter FUNCTION dbo.funkcja(@lp decimal (10,1))
returns decimal(10,1)
as
begin
declare @temp decimal(10,1)
while 0<1
begin
set @temp = null
select @temp = convert(decimal(10,1), adres1 + lp1/10.0 )
from dbo.paczki where adres2 =CONVERT(int, @lp)
and lp2 =substring(CONVERT(varchar(10),@lp),charindex('.',@lp)+1,100)
if @temp is null break else set @lp = @temp
end
return @lp
end
---------------------
select *,dbo.funkcja(800.8)from dbo.paczki
Wygląda to jak wygląda ale działa, może uda mi sie to przerobić na funkcje tabelaryczną, albo ktoś by mi pomógł :)
A musi być koniecznie funkcja? Nie lepiej zrobić sobie widok? Dziś chcesz odpytać bazę o jedną paczkę, a kiedyś może Ci się zamarzyć zrobić jakiś listing - będziesz wtedy budował osobną funkcję tabelaryczną i kleił dane w pętli? Nie tędy droga.
Polecam zrobić coś takiego:
CREATE VIEW dbo.v_paczki
AS
WITH CTE
AS (
SELECT ADRES2, LP2, ADRES1, LP1, 0 AS KROK
FROM PACZKI
UNION ALL
SELECT CTE.ADRES2, CTE.LP2, P.ADRES1, P.LP1, CTE.KROK+1
FROM CTE
JOIN PACZKI P ON P.ADRES2 = CTE.ADRES1
AND P.LP2 = CTE.LP1
)
SELECT CTE.*, CASE WHEN EXISTS(SELECT * FROM PACZKI p0 WHERE p0.ADRES2=CTE.ADRES1 AND p0.LP2=CTE.LP1) THEN 0 ELSE 1 END OSTATNI
FROM CTE
I teraz odpytujesz
SELECT * FROM V_PACZKI
WHERE
ADRES2=800 AND LP2=8
AND OSTATNI=1 --jeśli wykomentujesz tę linię, zapytanie zwróci całą historię tej jednej paczki
Fac napisał(a):
A musi być koniecznie funkcja? Nie lepiej zrobić sobie widok? Dziś chcesz odpytać bazę o jedną paczkę, a kiedyś może Ci się zamarzyć zrobić jakiś listing - będziesz wtedy budował osobną funkcję tabelaryczną i kleił dane w pętli? Nie tędy droga.
Polecam zrobić coś takiego:
CREATE VIEW dbo.v_paczki AS WITH CTE AS ( SELECT ADRES2, LP2, ADRES1, LP1, 0 AS KROK FROM PACZKI UNION ALL SELECT CTE.ADRES2, CTE.LP2, P.ADRES1, P.LP1, CTE.KROK+1 FROM CTE JOIN PACZKI P ON P.ADRES2 = CTE.ADRES1 AND P.LP2 = CTE.LP1 ) SELECT CTE.*, CASE WHEN EXISTS(SELECT * FROM PACZKI p0 WHERE p0.ADRES2=CTE.ADRES1 AND p0.LP2=CTE.LP1) THEN 0 ELSE 1 END OSTATNI FROM CTE
I teraz odpytujesz
SELECT * FROM V_PACZKI WHERE ADRES2=800 AND LP2=8 AND OSTATNI=1 --jeśli wykomentujesz tę linię, zapytanie zwróci całą historię tej jednej paczki
Dzieki, takie rozwiązanie jest nawet lepsze :)