Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: [inny]Jak połączyć dwie kolekcje po kluczu
Forum PHP.pl > Forum > PHP > Frameworki
fumfel20
Witam, Panowie mam dwie kolekcje, pierwsza to ilosc ktora zostala wyprodukowana (part_no, qty) danego panela:


Druga to taki ala plan:


Problem polega na tym ze pochodzą z oddzielnych baz danych wiec nie moge tego polaczyc joinem. Co trzeba zrobic zeby uzyskac taki rezultat:
  1. 0 => {#16621
  2. +"ifsCode": "KE.206.090.LV" <- to polaczyc z part_no
  3. +"description": "720x390x18(972) Base L Cnr Back B Lava (8mm grv)"
  4. +"minStock": "25"
  5. +"maxStock": "25"
  6. +"demand": "1"
  7. +"finishedStock": "45"
  8. +"inStock": "42"
  9. +"cover": "45"
  10. +"currentStock": "42"
  11. +"autoPlan": "0"
  12. +"totalAutoPlan": "0"
  13. +"qty": null <- a tu wstawic QTY ale z poprzedniej kolekcji
  14. }


Powiem szczedrze ze wczoraj szukalem rozwiazania ze 3 godziny i nie udalo mi sie. Bede wdzięczny za pomoc. PS: Framework to Laravel 5.6
rad11
A kto Ci powiedzial ze nie mozesz zrobic joina z dwoch baz danych ? Jesli te dwie bazy sa z jednego polaczenia to mozesz to zrobic tak:

  1. SELECT * FROM db1.table1 t1 LEFT JOIN db2.table2 t2 ON t1.id = t2.id


Ewentualnie jesli to jest z dwoch innych polaczen uzyj :

https://dev.mysql.com/doc/refman/8.0/en/fed...age-engine.html

Ale to wymaga nowszych wersji mysql.

Ostatecznie mozesz pobrac dane przemapowac na tablice gdzie kluczem bedzie part_no i przeleciec w drugiej petli wycisgajac dane weflug klucza part_no zwracajac uwage na to aby bylo aktywne polaczenie do tej tabelki z part_no
fumfel20
Sorki, nie napisałem chyba wszystkiego. Pierwsza baza to jest baza Oracle do której sie podpiąłem a druga to jest moja lokalna.
rad11
To raczej nie unikniesz trzeciej opcji.
fumfel20
Wczesniej rozwiazałem ten problem ale połowicznie, bo po prostu zawartosc tej kolekcji zapisuje w lokalnej bazie danych i potem do niej juz łączę joinem. Działa ale za dlugo to trwa. Az ciężko uwierzyć ze nie ma innej opcji.
rad11
Nie powinno to dlugo trwac pokaz jak to robiles i pokaz create tych tabelek
fumfel20
Problem polega na tym ze czasem paru userów chce sprawdzić w tym samym czasie to samo albo inny zakres dat wiec dlugo czekają.

Nie jestem teraz przy projekcie ale wyglada to mniej wiecej tak: User wybiera na przyklad date 2018-09-17. po tym nastepuje kasowanie tabeli lokalnej History, nastepnie zapytanie pobiera z bazy Oracle wszystkie rekordy dla okreslonej grupy produktow od tej daty wlacznie. To co zostalo pobrane insertem importowane jest do tabeli history i ostatnie zapytanie juz wyciaga liste produktów wszystkich a join łączy to po part_no. TO wszystko
rad11
Moim zdaniem nie tedy droga. Powiniennes zrobic skrypt ktory bedzie ta tabelke aktualizowal co jakis czas (cron), dodac odpowiednie indexy na kolumny itd.
fumfel20
Ok, zainteresowales mnie. Tylko prawdopodobnie to bedzie wygladalo tak ze musi tam byc historia nawet z przed roku. Nawet nie chce myslec ile tam bedzie rekordow.
rad11
To dowiedz sie ile bedzie tych rekordow i wtedy bedziesz sie martwic ale chyba w miliardach to nie bedzie. Ewentualnie jak bedzie bardzo bardzo duzo to spróbuj uzyc https://dev.mysql.com/doc/refman/5.7/en/par...ning-types.html

Oczywiscie piszac skypt mialem na mysli komende w Laravel itd.
fumfel20
Ok sprawdzilem. To bedzie okolo 5 mln od poczatku roku :/ I stale rosnie
Pyton_000
Dla czego nie pobierzesz od razu kolekcji i jako klucz ustawisz part_no a potem po prostu 1 pętlą przelecisz po quantity nadając wartości
fumfel20
Tu chyba wychodzą moje braki wiedzy bo nie wiem jak i jakos jak staralem sie wyszukac o tym informacje to nic mi nie wychodzilo, znalazlem tez w dokumentacji cos takiego:

  1. $latestPosts = DB::table('posts')
  2. ->select('user_id', DB::raw('MAX(created_at) as last_post_created_at'))
  3. ->where('is_published', true)
  4. ->groupBy('user_id');
  5.  
  6. $users = DB::table('users')
  7. ->joinSub($latestPosts, 'latest_posts', function($join) {
  8. $join->on('users.id', '=', 'latest_posts.user_id');
  9. })->get();


Ale nie zadzialalo. Pomozesz?
rad11
Ale co Ty tymi dwoma zapytaniami probujesz uzyskac ? To sa te dwie tabelki o ktorych pisales ?
fumfel20
Nie to jest przyklad z dokumentacji. Juz po prostu probowalem olac kolekcje i laczyc zapytania ale ostatecznie wolalbym sie skupic na polaczeniu kolekcji. W jakis sposob
rad11
To prosba abys nie dawal mi przykladow z dokumentacji tylko kod ktory piszesz ok?☺
fumfel20
Ok. Ale kodu tych kolekcji nie bede Ci dawal bo jak kolekcja wyglada to wiesz smile.gif. Zainteresowal mnie ten post kolegi Pyton_000. Moze faktycznie istnieje jakis sposob zeby to zrobić kolekcjami.
Tu jest kod gdzie pobieram kolekcje. ifsCode to jest to samo co part_no:
Kod
$planDate = $request->planDate;

        $imaPlan = collect(DB::connection('mysql')->select("
            select ip.ifsCode, ip.description, ip.minStock, ip.maxStock, ip.demand, ip.finishedStock, ist.inStock ,ip.cover,
            (CASE WHEN ist.inStock is null then 0 else ist.inStock END) as currentStock, ip.autoPlan ,ip.totalAutoPlan, ith.qty
            from imaProdPlan ip
            left join imaTransactionHistory ith on ith.partNo = ip.ifsCode
            left join imaStock ist on ist.partNo = ip.ifsCode
            where left(ip.created_at,10) = '$planDate'
        "));


        $ifsCodes = DB::connection('mysql')->select("SELECT distinct ifsCode from imaProdPlan");
        foreach ($ifsCodes as $key) {
            $ifsCodestr[] = "'".$key->ifsCode . "'";
        }
        $ifsCodestr = implode(", ", $ifsCodestr);
        //return dd($ifsCodestr);
        $th = collect(DB::connection('oracle')->select("select part_no, sum(quantity) as qty  from (
            select * from IFSAPP.INVENTORY_TRANSACTION_HIST2
            where contract = 'B001'
            and part_no in ($ifsCodestr)
            and to_char(date_applied, 'yyyy-mm-dd')
            BETWEEN to_char(to_date('$planDate','yyyy-mm-dd')-1,'yyyy-mm-dd') and to_char(to_date('$planDate','yyyy-mm-dd')+6,'yyyy-mm-dd')
            and DIRECTION = '+'
            and TRANSACTION = 'Receipt into Inventory'
            and LOCATION_NO = 'IMAPROD1')
            group by part_no"));
rad11
Istnieje nawet Ja Ci taka opcje podalem
fumfel20
No tak, nie widzialem Twojego edytowanego postu. Wlasnie problem polega na tym ze nie wiem jak sie za to zabrac. Domyslam sie ze metida map z kolekcji. Wracam do dokumentacji i jeszcze raz sprawdze.
rad11
Spróbuj tak:

  1.  
  2. $firstCollection = $collection->keyBy('part_no')->all();
  3.  
  4. $secodCollection = $collection->map(function ($row) use ($firstCollection){
  5.  
  6. $row['qty'] = $firstCollection[$row['ifsCode']]['qty'] questionmark.gif null;
  7.  
  8. // lub $row->qty = $firstCollection[$row->ifsCode]->qty questionmark.gif null
  9.  
  10. return $row;
  11.  
  12. });
fumfel20
PS: w pierwszym zapytaniu jest cos co powinienem wylaczyc, mianowicie:
left join imaTransactionHistory ith on ith.partNo = ip.ifsCode

Poniewaz to jest stare polaczenie ktore łączyło do tabeli z dumpem z Oracle. Wiec i w tej kolekcji nie bedzie QTY, QTY trzeba przeniesc z kolejnej kolekcji.

  1. (1/1) Error
  2. Cannot use object of type stdClass as array


  1. $first = $th->keyBy('part_no')->all();
  2. $sec = $imaPlan->map(function ($row) use ($first){
  3. $row['qty'] = $first[$row['ifsCode']]['qty'];
  4. });
  5.  
  6. return dd($row);


wywalilem "? null" bbo phpstorm podkreslal jako blad
rad11
Przyjrzyj sie dokladnie mojej odpowiedzi uzyj tej opcji co dodalem w komentarzu. questionmark.gif Powinien byc jesli uzywasz php >= 7 natomiast jezeli mniejszej wersji to musisz zrobic ifa i pozatym nie zwracasz w te funkcji nic
fumfel20
ok, mam PHP 7.2.* wiec powinno latac. Ide testowac i dam znac

Cytat(rad11 @ 23.09.2018, 16:01:32 ) *
Spróbuj tak:

  1.  
  2. $firstCollection = $collection->keyBy('part_no')->all();
  3.  
  4. $secodCollection = $collection->map(function ($row) use ($firstCollection){
  5.  
  6. $row['qty'] = $firstCollection[$row['ifsCode']]['qty'] questionmark.gif null;
  7.  
  8. // lub $row->qty = $firstCollection[$row->ifsCode]->qty questionmark.gif null
  9.  
  10. return $row;
  11.  
  12. });


Kurde, podkresla mi intelisense:

rad11
Bo tam powinny bycdwa znaki zapytania i return $row...
fumfel20



:/
Wywala blad: Cannot use object of type stdClass as array
rad11
Napisalem Ci ktory przyklad masz użyć popatrz jeszcze raz dokladnie
fumfel20
Robie cos zle i nie wiem co:


rad11
W use daj $th...
viking
https://laravel-news.com/laravel-view-models
fumfel20
Cytat(rad11 @ 24.09.2018, 09:40:59 ) *
W use daj $th...


EDIT:

wywalilem mojego dumpa i return $row nic mi nie zrwocil. Skrypt zatrzymal sie na moim pozniejszym returnie z komunikatem stop;

EDIT:
zrobilem dump ($imaPlan) i chyba jest ok:


Sprawdze jeszcze czy dobre liczby podstawil ale na koncu dodal tez pole part_no null.
EDIT: Tak testuje to wszystko i mam maly problem. Kolekcja imaProd jak widzisz zawiera joina do niepotrzebnego juz dumpa z kolekcji th, mianowicie "left join imaTransactionHistory ith on ith.partNo = ip.ifsCode". Wiec wywalilem na chwile tego lefta i dalem 0 as qty:
  1. select ip.ifsCode, ip.description, ip.minStock, ip.maxStock, ip.demand, ip.finishedStock, ist.inStock ,ip.cover,
  2. (CASE WHEN ist.inStock is null then 0 else ist.inStock END) as currentStock, ip.autoPlan ,ip.totalAutoPlan, 0 as qty
  3. from imaProdPlan ip
  4. -- left join imaTransactionHistory ith on ith.partNo = ip.ifsCode
  5. left join imaStock ist on ist.partNo = ip.ifsCode
  6. where left(ip.created_at,10) = '$planDate'


Problem polega na tym ze wtedy tego 0 juz nie podmienia mi funkcja map tylko wszedzie jest 0.

EDIT: Wyglada na to ze nic nie dziala. Dalej czyta dane z tabeli w ktorej jest poprzedni DUMP z $th.
To jest wersja lo-fi głównej zawartości. Aby zobaczyć pełną wersję z większą zawartością, obrazkami i formatowaniem proszę kliknij tutaj.
Invision Power Board © 2001-2025 Invision Power Services, Inc.