133 lines
8.0 KiB
Markdown
133 lines
8.0 KiB
Markdown
# Rapoarte SQL (meniu Rapoarte → „Rapoarte SQL")
|
|
|
|
Mecanism de raportare **fără `.frx`**: SQL-ul stă în baza de date, aplicația îl execută și afișează
|
|
rezultatul într-un grid (cu grupare/ordonare/export Excel). Se instalează printr-un script de
|
|
migrare, nu prin VFP IDE.
|
|
|
|
## Lansare și drepturi
|
|
|
|
- `Meniuri\rapoarte.mn2:36-37` → `DO alege_raport WITH 2, .T. IN orapoarte_dinamice.prg`.
|
|
- `alege_raport` (`COMUN\programe\orapoarte_dinamice.prg:5-79`): al doilea parametru `tlDrepturi=.T.`
|
|
⇒ lista se face cu **`join rapoarte_utilizatori ru on ... and ru.id_utilizator = gnIdUtil`**.
|
|
**Un raport fără linii în `RAPOARTE_UTILIZATORI` nu apare deloc în meniu**, oricât de corect ar fi.
|
|
- `executa_raport(tnIdFormularRaport, tnIdRaport)` (`:85-107`) deschide direct un raport după id,
|
|
fără lista de alegere.
|
|
|
|
`ID_FORMULAR_RAPORT` alege formularul:
|
|
|
|
| valoare | formular | ce e |
|
|
|---|---|---|
|
|
| 1 | `frm_date_rapoarte_rulaje` | rapoarte bazate pe rulaje |
|
|
| **2** | **`frm_date_rapoarte_sql`** (`COMUN\clase\orapoarte.vc2:4076`) | **rapoarte SQL** |
|
|
| 3 | `frm_date_rapoarte_balpart` | balanță parteneri |
|
|
|
|
## Tabele
|
|
|
|
- **`RAPOARTE`** — `CSQL` (CLOB, textul SQL), `CSQL_PARAMETRI` (XML, definiția parametrilor),
|
|
`DENUMIRE` (numele din listă, VARCHAR2(1000)), `TITLU` (titlul listării, 150), `ID_FORMULAR_RAPORT`,
|
|
`STERS`. Secvență: `SEQ_RAPOARTE`. View de listare: `VRAPOARTE`.
|
|
- **`RAPOARTE_FILTRE`** — o linie per raport, `VALOARE` = șir concatenat
|
|
`titlu;camp;pozitie_semn;;valoare|` (ex. `AN;AN;1;;0|LUNA;LUNA;1;;0|`). Generat de
|
|
`parametri_rapoarte_sql` (`orapoarte_dinamice.prg:186-206`), citit la deschidere
|
|
(`orapoarte.vc2:2709`). Marcajul `luna_curenta|` e înlocuit la citire cu luna/anul de lucru.
|
|
- **`RAPOARTE_UTILIZATORI`** — `(ID_RAPORT, ID_UTILIZATOR)`, drepturile. FK-uri către `RAPOARTE`:
|
|
doar `RAPOARTE_FILTRE` și `RAPOARTE_UTILIZATORI`.
|
|
|
|
## Parametri `<%=NUME%>`
|
|
|
|
În `CSQL` parametrii se scriu `<%=AN%>`, `<%=LUNA%>`. La rulare,
|
|
**`ct_selectie_sql.do_instructiune_sql`** (`COMUN\clase\orapoarte.vc2:1552-1637`) înlocuiește
|
|
**textual** (`STUFFC`) fiecare marcaj cu valoarea din criteriile de selecție — **nu sunt bind
|
|
variables**, deci valoarea intră brut în SQL.
|
|
|
|
Cuvinte rezervate, completate automat din globale (`orapoarte.vc2:1578-1586`):
|
|
|
|
| parametru | sursă |
|
|
|---|---|
|
|
| `AN` | `gnAn` |
|
|
| `LUNA` | `gnLuna` |
|
|
| `SUCURSALA` | `gcCondSucursala` |
|
|
|
|
Acestea **trebuie declarate cu `tipcamp = 'E'`**, iar `campid` = numele parametrului; altfel valoarea
|
|
nu se rezolvă și apare „Nu este completata valoarea parametrului X!".
|
|
|
|
Valoarea tastată de utilizator pentru un parametru rezervat este **ignorată** — se pune global. Deci
|
|
un interval (ex. lunile 1..7) cere doi parametri `tipcamp = 'N'` cu **alt nume**, iar numele nu are
|
|
voie să înceapă cu `AN`/`LUNA`/`SUCURSALA`: potrivirea din `do_instructiune_sql` e `=` VFP, iar cu
|
|
`SET EXACT OFF` un `LUNA_DE_LA` s-ar potrivi cu `LUNA`. Ex. `DE_LA_LUNA` / `PANA_LA_LUNA`, folosite
|
|
în SQL ca `luna between <%=DE_LA_LUNA%> and <%=PANA_LA_LUNA%>`.
|
|
|
|
Parametrul e citit din expresia de filtru spartă pe `AND` și apoi pe `=`, deci **merge doar operatorul
|
|
„egal"** (implicit la `N`) și numele nu poate conține `AND`.
|
|
|
|
`CSQL_PARAMETRI` = XML `VFPData` (encoding `Windows-1252`), câte un nod `crsparametri` cu
|
|
`parametru / titlu / camp / tipcamp / campid` (+ opțional `campcautare`); citit cu `XMLTOCURSOR` în
|
|
`criterii_rapoarte_sql` și `parametri_rapoarte_sql` (`orapoarte_dinamice.prg:109-251`).
|
|
`tipcamp`: `N` numeric, `C` caracter, `D` dată, `D1` perioadă (se traduce în `AN*12+LUNA`),
|
|
`E` cuvânt rezervat.
|
|
|
|
## Instalare printr-un script de migrare
|
|
|
|
Șablon de urmat: `D:\ROA\DATABASE\SCRIPTURI_CLAR\2026\07\ff_2026_07_23_01_GESTIUNE_RAPOARTE.sql`
|
|
(raportul `CHELTUIELI CUMULAT - REG JURNAL + RULAJE`, peste view-ul `VRUL_ACT_CHELTUIELI`) și
|
|
`...\2026\08\ff_2026_08_24_03_GESTIUNE_RAPOARTE.sql` (`VENITURI SI CHELTUIELI - REG JURNAL +
|
|
RULAJE`, view-urile `VRUL_ACT_VEN_CHELT_DET` + `VRUL_ACT_VEN_CHELT_TOT`). Structura:
|
|
|
|
1. `CREATE OR REPLACE VIEW` cu logica raportului (SQL-ul din `CSQL` rămâne un `select` simplu peste
|
|
view — mai ușor de depanat și de refolosit).
|
|
2. Bloc anonim idempotent: `IF (select count(*) from rapoarte where upper(denumire) = '...') = 0`
|
|
→ `SEQ_RAPOARTE.nextval` + `MERGE` în `RAPOARTE` + `MERGE` în `RAPOARTE_FILTRE` + `INSERT` în
|
|
`RAPOARTE_UTILIZATORI` din `syn_vutilizatori` ⋈ `syn_vdef_util_firme` ⋈
|
|
`syn_nom_firme where schema = user and nvl(sters,0) = 0`, cu `inactiv = 0`.
|
|
3. `exec pack_migrare.UpdateVersiune('<nume_script>'); commit;`
|
|
|
|
### Capcane
|
|
|
|
- **Commit.** Blocurile anonime nu comit singure. Rulat dintr-un client care nu comite la ieșire,
|
|
view-urile rămân create (DDL = commit implicit) dar raportul lipsește din `RAPOARTE` — arată exact
|
|
ca o problemă de drepturi. Verificare rapidă: `SEQ_RAPOARTE.last_number` a avansat, dar
|
|
`select * from rapoarte` nu are linia ⇒ lipsește `commit`.
|
|
- Drepturile nu sunt opționale (vezi mai sus).
|
|
- **`ACT.ID_PARTD` / `ACT.ID_PARTC` sunt `0` când nu există partener, niciodată `NULL`.** Un
|
|
`MIN(ID_PARTD)` peste notele unui document întoarce `0` și numele partenerului iese gol; corect e
|
|
`MIN(NULLIF(ID_PARTD, 0))`. Numele se iau din `NOM_PARTENERI.NUME` (în `VACT_TOT` sunt deja
|
|
rezolvate ca `PARTD`/`PARTC`).
|
|
- Ordinea coloanelor din `select`-ul din `CSQL` = ordinea coloanelor din grid.
|
|
- `ORDER BY` se scrie în `CSQL`; coloanele tehnice de sortare pot fi selectate sau nu, dar trebuie să
|
|
existe în view.
|
|
|
|
### Linii de total în același raport
|
|
|
|
Pentru totaluri la finalul listării (fără al doilea raport): `UNION ALL` cu rânduri sintetice care au
|
|
coloana de grupare **`NULL`** (Oracle sortează `NULLS LAST` la `ASC`, deci ajung ultimele) și un
|
|
`R_TIP` mai mare decât cele de detaliu; eticheta se pune într-o coloană text lată (`EXPLICATIA`),
|
|
valoarea în coloana de sumă. Exemplu: `VRUL_ACT_VEN_CHELT_TOT`, `R_TIP` 9-15.
|
|
|
|
Când raportul merge pe un **interval** de perioade, totalurile nu pot sta în view: view-ul le poate
|
|
da doar pe perioadă (altfel rândul agregat are `an`/`luna` `NULL` și cade la filtrul exterior). Deci
|
|
view-ul dă totalurile **pe lună**, iar `UNION ALL`-ul din `CSQL` le însumează pe intervalul cerut
|
|
(`group by r_tip, tip, explicatia`) — toate liniile fiind sume, adunarea pe luni e validă. Ramura de
|
|
totaluri pune `NULL` pe `an`/`luna`, deci blocul iese o singură dată, la finalul listării.
|
|
|
|
### Performanță: `WITH` materializat blochează filtrul de perioadă
|
|
|
|
Într-un view de raport filtrat pe `an`/`luna`, o subinterogare `WITH` **referită de două ori** e
|
|
materializată de Oracle într-un tabel temporar (`TEMP TABLE TRANSFORMATION` în plan). O subinterogare
|
|
materializată **nu mai primește predicatul exterior**: se construiește tot istoricul și abia la final
|
|
se aplică `an = ... and luna = ...`. Pe date de producție asta a însemnat 7.4M rânduri și un plan de
|
|
3h15m pentru o lună (`VRUL_ACT_VEN_CHELT`, versiunea inițială).
|
|
|
|
- `/*+ INLINE */` în CTE **nu** a rezolvat-o când CTE-ul e un `UNION ALL`.
|
|
- Ce funcționează: **view-uri separate în loc de CTE-uri referite de mai multe ori** — view-urile se
|
|
îmbină (view merging) și primesc predicatul. Vezi `VRUL_ACT_VEN_CHELT_DET` (detaliul) +
|
|
`VRUL_ACT_VEN_CHELT_TOT` (totalurile pe lună, agregă `_DET`) în
|
|
`SCRIPTURI_CLAR\2026\08\ff_2026_08_24_03_GESTIUNE_RAPOARTE.sql`.
|
|
- Subinterogările auxiliare (ancore de dată, teste de existență, totaluri de control) citesc
|
|
**tabelele de bază `ACT` / `RUL`**, nu `VACT_TOT` / `VRUL_TOT`: view-urile astea nu filtrează
|
|
rânduri (doar left join-uri de nomenclator), dar `VRUL_TOT` are `FDOC`/`ID_FDOC` ca **subinterogări
|
|
scalare pe `ACT` per rând**. Indecși utili: `ACT` `IDX_ACT_006 (AN,LUNA,STERS,…)`,
|
|
`IDX_ACT_002 (LUNA,AN,SCD,SCC,STERS,…)`; `RUL` `IDX_RUL_003 (AN,LUNA,COD)`.
|
|
- Verificare rapidă înainte de livrare: `EXPLAIN PLAN` pe interogarea din `CSQL` cu an/luna
|
|
concrete — dacă apare `TEMP TABLE TRANSFORMATION` sau predicatul `AN=`/`LUNA=` nu se vede la
|
|
accesele pe `ACT`/`RUL`, raportul va scana tot istoricul.
|