Natknąłem się na scenariusz, w którym muszę zwrócić złożony zestaw obliczonych wartości w punkcie przecięcia od „starszego” do obecnego.
Krótko mówiąc mam coś takiego...
with someofit as
(
select id, col1, col2, col3 from table1
)
select someofit.*,
case when id < @lastLegacyId then
(select ... from table2 where something = id) as 'bla'
,(select ... from table2 where something = id) as 'foo'
,(select ... from table2 where something = id) as 'bar'
else
(select ... from table3 where something = id) as 'bla'
,(select ... from table3 where something = id) as 'foo'
,(select ... from table3 where something = id) as 'bar'
end
from someofit
Nie, tutaj leży problem ... Nie chcę ciągle sprawdzać tej sprawy dla każdego podwyboru, ale w tym samym czasie, gdy ten warunek ma zastosowanie, potrzebuję wszystkich wyborów w odpowiednim bloku spraw.
Czy jest mądrzejszy sposób, aby to zrobić?
Gdybym był w odpowiednim języku OO użyłbym czegoś takiego...
var common = GetCommonSuff()
foreach (object item in common)
{
if(item.id <= lastLegacyId)
{
AppendLegacyValuesTo(item);
}
else
{
AppendCurrentValuesTo(item);
}
}
Początkowo próbowałem wykonać 2 pełne selekcje ze złączem, ale to nie działa zbyt dobrze ze względu na wydajność / liczbę wierszy do oceny.
Wybory podrzędne szukają łącznej liczby wierszy, w których spełniony jest jakiś warunek inny niż dopasowanie id w tabeli 2 lub 3, ale te tabele mogą zawierać miliony wierszy.
Cte jest używany z 2 powodów ...
Najpierw pobiera tylko wiersze z tabeli 1, która mnie interesuje, więc od razu wykonuję tylko ułamek podselekcji w każdym przypadku.
Po drugie zwraca typowe rzeczy w pojedynczym wyszukiwaniu w tabeli 1
Jakieś pomysły?
EDYCJA 1:
Jakiś kontekst sytuacji...
Mam tabelę o nazwie „importy” (tabela 1 powyżej), która reprezentuje zadanie importu, w którym pobieramy dane z pliku (csv lub podobnego) i pobieramy rekordy do bazy danych.
Następnie mam tabelę o nazwie „kroki”, która reprezentuje reguły przetwarzania / czyszczenia, przez które przechodzimy, a każdy rekord zawiera nazwę sproc i kilka innych rzeczy dotyczących reguły.
Istnieje wtedy tabela sprzężenia, która reprezentuje regułę dla konkretnego importu „ImportSteps” (tabela 2 powyżej - dla danych bieżących), zawiera kolumnę „rowsaffected” i identyfikator importu
Więc dla obecnych prac mój sql jest dość prosty ...
Wybierz 123 456 z importów dołącz do importsteps
W przypadku starszych starszych rzeczy muszę jednak przejrzeć tabelę 3 ... tabela 3 jest tabelą przechowującą, zawiera każdy rekord kiedykolwiek zaimportowany, każdy wiersz ma identyfikator importu, a każdy wiersz zawiera wartości kluczy.
W nowych wierszach danych w tabeli 2 dla identyfikatora importu x, gdzie identyfikator kroku to y, zwróci moją wartość.
Na starszych danych muszę policzyć wiersze w gospodarstwie, gdzie col z = coś
Potrzebuję danych na temat około 20 importów, a dane te są powiązane z „siatką danych” w mojej aplikacji internetowej mvc (jeśli to ma jakiekolwiek znaczenie)
Cte, którego używam, określa za pomocą niektórych parametrów „bieżące 20 osób, które mnie interesują” te parametry reprezentują rekord początkowy i końcowy (uporządkowane według identyfikatora importu).
Moim największym problemem jest to, że trzymanie tabeli ... jest ogromne ... wiadomo, że pojedyncze zadania zawierają 500 000 + rekordów samodzielnie, a ta tabela zawiera wiele importowanych wierszy, więc potrzebuję, aby moje wyszukiwania w tej tabeli były tak szybkie, jak to możliwe i jak najmniej.
EDYCJA 2:
Rzeczywiste rozwiązanie (tylko kod zamszowy) ...
-- declare and populate the subset to reduce reads on the big holding table
declare table @holding ( ... )
insert into @holding
select .. from holding
select
... common stuff from inner select in "from" below
... bunch of ...
case when id < @legacy then (select getNewValue(id, stepid))
else (select x from @holding where id = ID and ... ) end as 'bla'
from
(
select ROW_NUMBER() over (order by importid desc) as 'RowNum'
, ...
) as I
-- this bit handles the paging
where RowNum >= @StartIndex
and RowNum < @EndIndex
Nadal jestem pewien, że mogę to uporządkować, ale moje pierwotne zapytanie, które wyglądało jak rozwiązanie dotyczące rachunków, miało około 45 sekund czasu wykonania, to jest około 7
2 odpowiedzi
Rozumiem, że podzapytania muszą zwracać pojedynczą wartość skalarną, prawda? Ten punkt jest ważny, ponieważ zapewnia, że LEFT JOIN nie pomnoży wyniku.
;with someofit as
(
select id, col1, col2, col3 from table1
)
select someofit.*,
bla = coalesce(t2.col1, t3.col1),
foo = coalesce(t2.col2, t3.col2),
bar = coalesce(t2.bar, t3.bar)
from someofit
left join table2 t2 on t2.something=someofit.id and somefit.id < @lastLegacyId
left join table3 t3 on t3.something=someofit.id and somefit.id >= @lastLegacyId
Uważaj, że użyłem id >= @lastLegacyId
jako uzupełnienia warunku, zakładając, że id nie jest nullable. Jeśli tak, potrzebujesz tam IsNull, tj. somefit.id >= isnull(@lastLegacyId,somefit.id)
.
Twoja edycja pytania nie zmienia faktu, że jest to prawie dosłowne tłumaczenie składni O-O.
foreach (object item in common) --> "from someofit"
{
if(item.id <= lastLegacyId) --> the precondition to the t2 join
{
AppendLegacyValuesTo(item); --> putting t2.x as first argument of coalesce
}
else --> sql would normally join to both tables
--> hence we need an explicit complement
--> condition as an "else" clause
{
AppendCurrentValuesTo(item); --> putting t3.x as 2nd argument
--> tbh, the order doesn't matter since t2/t3
--> are mutually exclusive
}
}
function AppendCurrentValuesTo --> the correlation between t2/t3 to someofit.id
Teraz, jeśli rzeczywiście tego spróbowałeś i to nie rozwiąże twojego problemu, chciałbym wiedzieć, gdzie to się zepsuło.
Zakładając, że wiesz, że nie ma sprzecznych identyfikatorów między dwiema tabelami, możesz zrobić coś takiego (składnia DB2, bo to wiem, ale powinno być podobnie):
with combined_tables as (
select ... as id, ... as bla, ...as bar, ... as foo from table 2
union all
select ... as id, ... as bla, ...as bar, ... as foo from table 3
)
select someofit.*, combined_ids.bla, combined_ids.foo, combined_ids.bar
from someofit
join combined_tables on someofit.id = combined_tables.id
Jeśli masz takie przypadki, jak nakładające się identyfikatory, możesz sobie z tym poradzić w sekcji Combined_tables()
Podobne pytania
Nowe pytania
sql-server
Microsoft SQL Server to system zarządzania relacyjnymi bazami danych (RDBMS). Użyj tego tagu dla wszystkich wersji SQL Server, w tym Compact, Express, Azure, Fast-track, APS (dawniej PDW) i Azure SQL DW. Nie używaj tego tagu dla innych typów DBMS (MySQL, PostgreSQL, Oracle itp.). Nie używaj tego tagu w przypadku problemów z oprogramowaniem i programowaniem mobilnym, chyba że jest on bezpośrednio powiązany z bazą danych.