# Manipulació dades

# Select data

La realització de consultes **`SELECT`** segures amb **clàusules `WHERE`** i la implementació de **paginació** són operacions fonamentals. Utilitzarem la tècnica de **Sentències preparades** per a la clàusula `WHERE` per garantir la seguretat contra la injecció SQL, i les clàusules **`LIMIT`** i **`OFFSET`** per a la paginació.

## MySQLi Procedural

Aquest mètode utilitza funcions prefixades amb `mysqli_` i punts d'interrogació (`?`) com a marcadors de posició.

### Consulta, filtre (`WHERE`) i paginació

<div _ngcontent-ng-c2268849367="" class="markdown markdown-main-panel enable-updated-hr-color" dir="ltr" id="bkmrk-" inline-copy-host=""></div><div _ngcontent-ng-c243700105="" class="code-block ng-tns-c243700105-215 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" id="bkmrk-php" jslog="223238;track:impression,attention;BardVeMetadataKey:[["r_cadaeafcd36dc7a3","c_f93da456ed382884",null,"rc_9c614b6d6a41e66d",null,null,"ca",null,1,null,null,1,0]]"><div _ngcontent-ng-c243700105="" class="code-block-decoration header-formatted gds-title-s ng-tns-c243700105-215 ng-star-inserted"><span class="ng-tns-c243700105-215">PHP</span><div _ngcontent-ng-c243700105="" class="buttons ng-tns-c243700105-215 ng-star-inserted"><button aria-label="Copiar código" class="mdc-icon-button mat-mdc-icon-button mat-mdc-button-base mat-mdc-tooltip-trigger copy-button ng-tns-c243700105-215 mat-unthemed _mat-animation-noopable ng-star-inserted"></button></div></div><div _ngcontent-ng-c243700105="" class="formatted-code-block-internal-container ng-tns-c243700105-215"><div _ngcontent-ng-c243700105="" class="animated-opacity ng-tns-c243700105-215"></div></div></div>```php
<?php
// Suposant que $conn és la connexió establerta
// Dades de Paginació (pàgina 2, 10 ítems per pàgina)
$elements_per_pagina = 10;
$pagina_actual = 2;
$offset = ($pagina_actual - 1) * $elements_per_pagina;
$limit = $elements_per_pagina;
$filtre_nom = 'A%'; // Cerca noms que comencin per 'A'

// 1. Preparar la sentència
// Ús de ? per al filtre WHERE. LIMIT i OFFSET es concatenen per a mysqli_prepare (és una limitació)
$sql = "SELECT nom, email FROM Usuaris WHERE nom LIKE ? LIMIT ?, ?";
$stmt = mysqli_prepare($conn, $sql);

// 2. Vincular les variables
// Tipus: 's' per a string, 'i' per a integer. IMPORTANT: L'offset i el limit han de ser 'i'
mysqli_stmt_bind_param($stmt, "sii", $filtre_nom, $offset, $limit);

// 3. Executar la sentència
mysqli_stmt_execute($stmt);

// 4. Obtenir el conjunt de resultats
$result = mysqli_stmt_get_result($stmt);

// 5. Processar i mostrar les dades
if (mysqli_num_rows($result) > 0) {
    echo "<h2>Resultats (MySQLi Procedural)</h2>";
    while ($row = mysqli_fetch_assoc($result)) {
        echo "Nom: " . $row['nom'] . " - Email: " . $row['email'] . "<br>";
    }
} else {
    echo "No s'han trobat resultats.";
}

// 6. Tancar
mysqli_stmt_close($stmt);
mysqli_close($conn);
?>
```

<div _ngcontent-ng-c243700105="" class="code-block ng-tns-c243700105-215 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" id="bkmrk--1" jslog="223238;track:impression,attention;BardVeMetadataKey:[["r_cadaeafcd36dc7a3","c_f93da456ed382884",null,"rc_9c614b6d6a41e66d",null,null,"ca",null,1,null,null,1,0]]"><div _ngcontent-ng-c243700105="" class="formatted-code-block-internal-container ng-tns-c243700105-215"><div _ngcontent-ng-c243700105="" class="animated-opacity ng-tns-c243700105-215"></div></div></div>## MySQLi Orientat a Objectes (OO)

Aquest mètode utilitza mètodes de l'objecte `$conn` i l'objecte `$stmt`.

### Consulta, filtre (`WHERE`) i paginació

<div _ngcontent-ng-c2268849367="" class="markdown markdown-main-panel enable-updated-hr-color" dir="ltr" id="bkmrk--2" inline-copy-host=""></div><div _ngcontent-ng-c243700105="" class="code-block ng-tns-c243700105-216 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" id="bkmrk-php-1" jslog="223238;track:impression,attention;BardVeMetadataKey:[["r_cadaeafcd36dc7a3","c_f93da456ed382884",null,"rc_9c614b6d6a41e66d",null,null,"ca",null,1,null,null,1,0]]"><div _ngcontent-ng-c243700105="" class="code-block-decoration header-formatted gds-title-s ng-tns-c243700105-216 ng-star-inserted"><span class="ng-tns-c243700105-216">PHP</span><div _ngcontent-ng-c243700105="" class="buttons ng-tns-c243700105-216 ng-star-inserted"><button aria-label="Copiar código" class="mdc-icon-button mat-mdc-icon-button mat-mdc-button-base mat-mdc-tooltip-trigger copy-button ng-tns-c243700105-216 mat-unthemed _mat-animation-noopable ng-star-inserted"></button></div></div><div _ngcontent-ng-c243700105="" class="formatted-code-block-internal-container ng-tns-c243700105-216"><div _ngcontent-ng-c243700105="" class="animated-opacity ng-tns-c243700105-216"></div></div></div>```php
<?php
// Suposant que $conn és l'objecte de connexió mysqli
// Dades de Paginació
$elements_per_pagina = 10;
$pagina_actual = 2;
$offset = ($pagina_actual - 1) * $elements_per_pagina;
$limit = $elements_per_pagina;
$filtre_nom = 'A%';

// 1. Preparar la sentència
$sql = "SELECT nom, email FROM Usuaris WHERE nom LIKE ? LIMIT ?, ?";
$stmt = $conn->prepare($sql);

// 2. Vincular les variables
$stmt->bind_param("sii", $filtre_nom, $offset, $limit);

// 3. Executar la sentència
$stmt->execute();

// 4. Obtenir el resultat
$result = $stmt->get_result();

// 5. Processar i mostrar les dades
if ($result->num_rows > 0) {
    echo "<h2>Resultats (MySQLi OO)</h2>";
    while ($row = $result->fetch_assoc()) {
        echo "Nom: " . $row['nom'] . " - Email: " . $row['email'] . "<br>";
    }
} else {
    echo "No s'han trobat resultats.";
}

// 6. Tancar
$stmt->close();
$conn->close();
?>
```

<div _ngcontent-ng-c243700105="" class="code-block ng-tns-c243700105-216 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" id="bkmrk--3" jslog="223238;track:impression,attention;BardVeMetadataKey:[["r_cadaeafcd36dc7a3","c_f93da456ed382884",null,"rc_9c614b6d6a41e66d",null,null,"ca",null,1,null,null,1,0]]"><div _ngcontent-ng-c243700105="" class="formatted-code-block-internal-container ng-tns-c243700105-216"><div _ngcontent-ng-c243700105="" class="animated-opacity ng-tns-c243700105-216"></div></div></div>## PDO (PHP Data Objects)

PDO és la forma més simple i segura per als selects, especialment en la vinculació de paràmetres.

### Consulta, filtre (`WHERE`) i paginació

<div _ngcontent-ng-c2268849367="" class="markdown markdown-main-panel enable-updated-hr-color" dir="ltr" id="bkmrk--4" inline-copy-host=""></div><div _ngcontent-ng-c243700105="" class="code-block ng-tns-c243700105-217 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" id="bkmrk-php-2" jslog="223238;track:impression,attention;BardVeMetadataKey:[["r_cadaeafcd36dc7a3","c_f93da456ed382884",null,"rc_9c614b6d6a41e66d",null,null,"ca",null,1,null,null,1,0]]"><div _ngcontent-ng-c243700105="" class="code-block-decoration header-formatted gds-title-s ng-tns-c243700105-217 ng-star-inserted"><span class="ng-tns-c243700105-217">PHP</span><div _ngcontent-ng-c243700105="" class="buttons ng-tns-c243700105-217 ng-star-inserted"><button aria-label="Copiar código" class="mdc-icon-button mat-mdc-icon-button mat-mdc-button-base mat-mdc-tooltip-trigger copy-button ng-tns-c243700105-217 mat-unthemed _mat-animation-noopable ng-star-inserted"></button></div></div><div _ngcontent-ng-c243700105="" class="formatted-code-block-internal-container ng-tns-c243700105-217"><div _ngcontent-ng-c243700105="" class="animated-opacity ng-tns-c243700105-217"></div></div></div>```php
<?php
// Suposant que $pdo és l'objecte de connexió PDO
// Dades de Paginació
$elements_per_pagina = 10;
$pagina_actual = 2;
$offset = ($pagina_actual - 1) * $elements_per_pagina;
$limit = $elements_per_pagina;
$filtre_nom = 'A%';

try {
    // 1. Preparar la sentència (utilitzant marcadors de posició '?')
    $sql = "SELECT nom, email FROM Usuaris WHERE nom LIKE ? LIMIT ? OFFSET ?";
    $stmt = $pdo->prepare($sql);

    // 2. Vincular i executar (la manera més neta)
    // IMPORTANT: PDO NO necessita definir els tipus (s, i, d), però sí que s'han de passar al mateix ordre.
    // L'offset i el limit han de ser int, per la qual cosa cal assegurar-se que $offset i $limit són numèrics.
    $stmt->execute([$filtre_nom, $limit, $offset]);

    // 3. Obtenir totes les dades com un array associatiu
    $resultats = $stmt->fetchAll(PDO::FETCH_ASSOC);

    // 4. Processar i mostrar les dades
    if (count($resultats) > 0) {
        echo "<h2>Resultats (PDO)</h2>";
        foreach ($resultats as $row) {
            echo "Nom: " . $row['nom'] . " - Email: " . $row['email'] . "<br>";
        }
    } else {
        echo "No s'han trobat resultats.";
    }

} catch (PDOException $e) {
    die("Error en la consulta: " . $e->getMessage());
}

// 5. Tancar
$pdo = null;
?>
```

<div _ngcontent-ng-c243700105="" class="code-block ng-tns-c243700105-217 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" id="bkmrk--5" jslog="223238;track:impression,attention;BardVeMetadataKey:[["r_cadaeafcd36dc7a3","c_f93da456ed382884",null,"rc_9c614b6d6a41e66d",null,null,"ca",null,1,null,null,1,0]]"><div _ngcontent-ng-c243700105="" class="formatted-code-block-internal-container ng-tns-c243700105-217"><div _ngcontent-ng-c243700105="" class="animated-opacity ng-tns-c243700105-217"></div></div></div><div _ngcontent-ng-c2268849367="" class="markdown markdown-main-panel enable-updated-hr-color" dir="ltr" id="bkmrk--6" inline-copy-host=""></div>### Paginació

La **paginació** es realitza a nivell de SQL mitjançant les clàusules **`LIMIT`** i **`OFFSET`**:

<div _ngcontent-ng-c2268849367="" class="markdown markdown-main-panel enable-updated-hr-color" dir="ltr" id="bkmrk-limit-n%3A-indica-el-n" inline-copy-host="">- **`LIMIT N`**: Indica el nombre màxim de files que es volen retornar (els elements per pàgina).
- **`OFFSET M`**: Indica el nombre de files que s'han de saltar des del principi del conjunt de resultats.

</div>La fórmula per calcular l'offset sempre és:

[![image.png](https://siensis.com/books/uploads/images/gallery/2025-10/scaled-1680-/N4FrLzFsrbXlRC3m-image.png)](https://siensis.com/books/uploads/images/gallery/2025-10/N4FrLzFsrbXlRC3m-image.png)

<div _ngcontent-ng-c2268849367="" class="markdown markdown-main-panel enable-updated-hr-color" dir="ltr" id="bkmrk--8" inline-copy-host=""><div class="math-block align-center" data-math="\text{offset} = (\text{pàgina\_actual} - 1) \times \text{elements\_per\_pàgina}">  
</div></div>

# Paginació

La **paginació** és un mecanisme essencial en el desenvolupament web i de bases de dades per dividir grans conjunts de dades en pàgines més petites i manejables. Això millora dràsticament el rendiment i l'experiència de l'usuari. El mètode de paginació més comú, es coneix com a **paginació basada en desplaçament (Offset)**. Funciona utilitzant les clàusules **`LIMIT`** i **`OFFSET`** de SQL per dir al motor de la base de dades que retorni només un subconjunt de les dades.

El procés es divideix en tres parts:

<div _ngcontent-ng-c2268849367="" class="markdown markdown-main-panel enable-updated-hr-color" dir="ltr" id="bkmrk-c%C3%A0lcul-de-par%C3%A0metres" inline-copy-host="">1. **Càlcul de Paràmetres (PHP/Servidor):** El servidor (PHP) determina quina pàgina s'està sol·licitant i quants registres s'han de saltar (`OFFSET`).
2. **Consulta SQL:** El servidor envia la consulta amb els valors `LIMIT` i `OFFSET` inserits de manera segura.
3. **Presentació:** La base de dades retorna només les dades sol·licitades, que es mostren a l'usuari, juntament amb els enllaços de "Pàgina Anterior" i "Pàgina Següent".

</div>### Fórmules

Assumim que `$elements_per_pagina` és el valor de `LIMIT` i `$pagina_actual` és el número de pàgina (començant per 1):

<div _ngcontent-ng-c2268849367="" class="markdown markdown-main-panel enable-updated-hr-color" dir="ltr" id="bkmrk-par%C3%A0metre-prop%C3%B2sit-f" inline-copy-host=""><table><thead><tr><td>**Paràmetre**</td><td>**Propòsit**</td><td>**Fórmula de Càlcul**</td></tr></thead><tbody><tr><td>**`LIMIT`**</td><td>Nombre màxim de registres a retornar (mida de la pàgina).</td><td>`$elements_per_pagina`</td></tr><tr><td>**`OFFSET`**</td><td>Nombre de registres a saltar des del principi.</td><td>`($pagina_actual - 1) * $elements_per_pagina`</td></tr></tbody></table>

</div>### Exemple SQL

Per obtenir la **tercera pàgina** amb **15 registres** per pàgina:

[![image.png](https://siensis.com/books/uploads/images/gallery/2025-10/scaled-1680-/ViUFLWiUsKklGa1y-image.png)](https://siensis.com/books/uploads/images/gallery/2025-10/ViUFLWiUsKklGa1y-image.png)

<div _ngcontent-ng-c243700105="" class="code-block ng-tns-c243700105-330 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" id="bkmrk-sql" jslog="223238;track:impression,attention;BardVeMetadataKey:[["r_1f8f61dc9b5a3b88","c_f93da456ed382884",null,"rc_65f691da10b05eff",null,null,"ca",null,1,null,null,1,0]]"><div _ngcontent-ng-c243700105="" class="code-block-decoration header-formatted gds-title-s ng-tns-c243700105-330 ng-star-inserted"><span class="ng-tns-c243700105-330">SQL</span><button aria-label="Copiar código" class="mdc-icon-button mat-mdc-icon-button mat-mdc-button-base mat-mdc-tooltip-trigger copy-button ng-tns-c243700105-330 mat-unthemed _mat-animation-noopable ng-star-inserted"></button></div><div _ngcontent-ng-c243700105="" class="formatted-code-block-internal-container ng-tns-c243700105-330"><div _ngcontent-ng-c243700105="" class="animated-opacity ng-tns-c243700105-330">  
</div></div></div>```sql
SELECT * FROM Orders ORDER BY id LIMIT 15 OFFSET 30;
-- Retorna 15 registres, començant pel registre 31.
```

<div _ngcontent-ng-c243700105="" class="code-block ng-tns-c243700105-330 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" id="bkmrk--1" jslog="223238;track:impression,attention;BardVeMetadataKey:[["r_1f8f61dc9b5a3b88","c_f93da456ed382884",null,"rc_65f691da10b05eff",null,null,"ca",null,1,null,null,1,0]]"><div _ngcontent-ng-c243700105="" class="formatted-code-block-internal-container ng-tns-c243700105-330"><div _ngcontent-ng-c243700105="" class="animated-opacity ng-tns-c243700105-330"></div></div></div><div _ngcontent-ng-c2268849367="" class="markdown markdown-main-panel enable-updated-hr-color" dir="ltr" id="bkmrk--2" inline-copy-host=""></div><p class="callout danger">**ATENCIÓ** L'`ORDER BY` és crucial; sense ell, els registres retornats podrien canviar a cada consulta</p>

### Avantatges

<div _ngcontent-ng-c2268849367="" class="markdown markdown-main-panel enable-updated-hr-color" dir="ltr" id="bkmrk-simplicitat%3A-el-conc" inline-copy-host="">- **Simplicitat:** El concepte de `LIMIT` i `OFFSET` és molt fàcil d'entendre i d'implementar en la majoria de bases de dades (MySQL, PostgreSQL, etc.).
- **Accessibilitat:** Permet accedir directament a qualsevol número de pàgina, cosa que facilita la creació d'interfícies amb un menú de navegació numèric (p. ex., 1, 2, 3, 4...).
- **Control del Motor:** Tota la lògica de salt de dades es delega al motor SQL, que és el més eficient per gestionar-ho.

</div>### Inconvenients (rendiment)

El principal desavantatge d'aquest mètode es manifesta en conjunts de dades molt grans i a pàgines molt avançades:

<div _ngcontent-ng-c2268849367="" class="markdown markdown-main-panel enable-updated-hr-color" dir="ltr" id="bkmrk-escalat-lent-%28slow-s" inline-copy-host="">- **Escalat lent (Slow Scaling):** Quan l'usuari demana una pàgina amb un `OFFSET` molt gran (p. ex., `OFFSET 100000`), el motor de la base de dades *encara ha de recórrer i descartar* 100.000 registres.
- **Bloqueig implícit:** Si les dades estan canviant ràpidament (insercions/eliminacions), la pàgina 3 consultada un minut més tard podria mostrar registres duplicats o ometre'n alguns, ja que els índexs de desplaçament no són estables en el temps.

</div>## Paginació basada en cursors (Keyset/Seek pagination)

Per superar les limitacions d'escalabilitat de l'`OFFSET`, s'utilitza la **Paginació basada en cursors** (o Keysets). En lloc de dir "salta 1000 registres", es pregunta: **"Dona'm els 20 registres següents a la ID 1000"**.

<div _ngcontent-ng-c2268849367="" class="markdown markdown-main-panel enable-updated-hr-color" dir="ltr" id="bkmrk--3" inline-copy-host=""></div><div _ngcontent-ng-c243700105="" class="code-block ng-tns-c243700105-331 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" id="bkmrk-sql-1" jslog="223238;track:impression,attention;BardVeMetadataKey:[["r_1f8f61dc9b5a3b88","c_f93da456ed382884",null,"rc_65f691da10b05eff",null,null,"ca",null,1,null,null,1,0]]"><div _ngcontent-ng-c243700105="" class="code-block-decoration header-formatted gds-title-s ng-tns-c243700105-331 ng-star-inserted"><span class="ng-tns-c243700105-331">SQL</span><button aria-label="Copiar código" class="mdc-icon-button mat-mdc-icon-button mat-mdc-button-base mat-mdc-tooltip-trigger copy-button ng-tns-c243700105-331 mat-unthemed _mat-animation-noopable ng-star-inserted"></button></div><div _ngcontent-ng-c243700105="" class="formatted-code-block-internal-container ng-tns-c243700105-331"><div _ngcontent-ng-c243700105="" class="animated-opacity ng-tns-c243700105-331">  
</div></div></div>```php
SELECT * FROM Orders WHERE id > 1000 ORDER BY id ASC LIMIT 20;
```

<div _ngcontent-ng-c243700105="" class="code-block ng-tns-c243700105-331 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" id="bkmrk--4" jslog="223238;track:impression,attention;BardVeMetadataKey:[["r_1f8f61dc9b5a3b88","c_f93da456ed382884",null,"rc_65f691da10b05eff",null,null,"ca",null,1,null,null,1,0]]"><div _ngcontent-ng-c243700105="" class="formatted-code-block-internal-container ng-tns-c243700105-331"><div _ngcontent-ng-c243700105="" class="animated-opacity ng-tns-c243700105-331"></div></div></div><div _ngcontent-ng-c2268849367="" class="markdown markdown-main-panel enable-updated-hr-color" dir="ltr" id="bkmrk--5" inline-copy-host=""></div>Això evita que el motor hagi de comptar i descartar files. Simplement utilitza l'índex de la columna (`id` en aquest cas) per anar directament al registre desitjat. Aquesta tècnica és molt **més ràpida i eficient** en escales grans, encara que limita la navegació a "Següent" i "Anterior" (no permet anar directament a la pàgina 50).

<div _ngcontent-ng-c2268849367="" class="markdown markdown-main-panel enable-updated-hr-color" dir="ltr" id="bkmrk--6" inline-copy-host=""></div>### Que passa si no hi ha ID numèric?

Fer una paginació Keyset (o Seek Pagination) quan els IDs no són numèrics és totalment possible. La clau és utilitzar una columna que sigui **ordenada** i **indexada** com a punt de referència (el cursor), tot i que aquesta no sigui l'ID principal. Normalment, s'utilitza una columna de **data/hora** o una combinació de la columna no numèrica i l'ID (per a desempat).

#### Ordre consistent i únic

El principi de Keyset Pagination és trobar el "pròxim" registre basant-se en el valor de l'últim registre vist. Això requereix un camp o una combinació de camps que siguin:

<div _ngcontent-ng-c2268849367="" class="markdown markdown-main-panel enable-updated-hr-color" dir="ltr" id="bkmrk-ordenables-%28order-by" inline-copy-host="">1. **Ordenables** (`ORDER BY`).
2. **Únics** o gairebé únics (per evitar saltar-se o duplicar registres).

</div>##### Paginació camps de Data/Hora (Timestamps)

Si el teu cursor no pot ser un ID numèric, el millor substitut és una columna **`TIMESTAMP`** o **`DATETIME`** ben indexada, ja que les dates són inherentment ordenables.

**Dades necessàries a cada petició:**

<div _ngcontent-ng-c2268849367="" class="markdown markdown-main-panel enable-updated-hr-color" dir="ltr" id="bkmrk-%24limit%3A-mida-de-la-p" inline-copy-host="">- `$limit`: Mida de la pàgina (p. ex., 20).
- `$ultima_data`: La data/hora de l'últim registre de la pàgina anterior.

</div>**Consulta SQL:**

<div _ngcontent-ng-c2268849367="" class="markdown markdown-main-panel enable-updated-hr-color" dir="ltr" id="bkmrk--8" inline-copy-host=""></div><div _ngcontent-ng-c243700105="" class="code-block ng-tns-c243700105-343 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" id="bkmrk-sql-2" jslog="223238;track:impression,attention;BardVeMetadataKey:[["r_e85bf8695a573c08","c_f93da456ed382884",null,"rc_6f009f4171a48282",null,null,"ca",null,1,null,null,1,0]]"><div _ngcontent-ng-c243700105="" class="code-block-decoration header-formatted gds-title-s ng-tns-c243700105-343 ng-star-inserted"><span class="ng-tns-c243700105-343">SQL</span><div _ngcontent-ng-c243700105="" class="buttons ng-tns-c243700105-343 ng-star-inserted"><button aria-label="Copiar código" class="mdc-icon-button mat-mdc-icon-button mat-mdc-button-base mat-mdc-tooltip-trigger copy-button ng-tns-c243700105-343 mat-unthemed _mat-animation-noopable ng-star-inserted"></button></div></div><div _ngcontent-ng-c243700105="" class="formatted-code-block-internal-container ng-tns-c243700105-343"><div _ngcontent-ng-c243700105="" class="animated-opacity ng-tns-c243700105-343"></div></div></div>```sql
SELECT * FROM Productes 
WHERE data_creacio < :ultima_data 
ORDER BY data_creacio DESC 
LIMIT :limit;
```

<div _ngcontent-ng-c243700105="" class="code-block ng-tns-c243700105-343 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" id="bkmrk--9" jslog="223238;track:impression,attention;BardVeMetadataKey:[["r_e85bf8695a573c08","c_f93da456ed382884",null,"rc_6f009f4171a48282",null,null,"ca",null,1,null,null,1,0]]"><div _ngcontent-ng-c243700105="" class="formatted-code-block-internal-container ng-tns-c243700105-343"><div _ngcontent-ng-c243700105="" class="animated-opacity ng-tns-c243700105-343"></div></div></div><div _ngcontent-ng-c2268849367="" class="markdown markdown-main-panel enable-updated-hr-color" dir="ltr" id="bkmrk-com-funciona%3A-busca-" inline-copy-host="">- **Com funciona:** Busca productes que siguin **anteriors** a la data de l'últim producte que vam veure.
- **Per a la primera pàgina:** Si `$ultima_data` és null, es pot utilitzar una data molt recent o un alias.

</div>##### Paginació combinació columnes (Desempat)

Si hi ha la possibilitat que dos registres tinguin exactament la mateixa data/hora de creació, necessitem una segona columna per desempatar. S'utilitza la columna no numèrica i després el camp ID (o qualsevol camp únic).

Imaginem que tens un camp **`codi_sku`** (string) i el vols utilitzar per ordenar.

**Dades necessàries a cada petició:**

<div _ngcontent-ng-c2268849367="" class="markdown markdown-main-panel enable-updated-hr-color" dir="ltr" id="bkmrk-%24limit%3A-mida-de-la-p-1" inline-copy-host="">- `$limit`: Mida de la pàgina.
- `$ultim_sku`: El valor `codi_sku` de l'últim registre de la pàgina anterior.
- `$ultim_id_unic`: El valor ID (o data/hora) de l'últim registre de la pàgina anterior.

</div>**Consulta SQL (Utilitzant `codi_sku` i `id` per desempat):**

<div _ngcontent-ng-c2268849367="" class="markdown markdown-main-panel enable-updated-hr-color" dir="ltr" id="bkmrk--10" inline-copy-host=""></div><div _ngcontent-ng-c243700105="" class="code-block ng-tns-c243700105-344 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" id="bkmrk-sql-3" jslog="223238;track:impression,attention;BardVeMetadataKey:[["r_e85bf8695a573c08","c_f93da456ed382884",null,"rc_6f009f4171a48282",null,null,"ca",null,1,null,null,1,0]]"><div _ngcontent-ng-c243700105="" class="code-block-decoration header-formatted gds-title-s ng-tns-c243700105-344 ng-star-inserted"><span class="ng-tns-c243700105-344">SQL</span><div _ngcontent-ng-c243700105="" class="buttons ng-tns-c243700105-344 ng-star-inserted"><button aria-label="Copiar código" class="mdc-icon-button mat-mdc-icon-button mat-mdc-button-base mat-mdc-tooltip-trigger copy-button ng-tns-c243700105-344 mat-unthemed _mat-animation-noopable ng-star-inserted"></button></div></div><div _ngcontent-ng-c243700105="" class="formatted-code-block-internal-container ng-tns-c243700105-344"><div _ngcontent-ng-c243700105="" class="animated-opacity ng-tns-c243700105-344"></div></div></div>```sql
SELECT codi_sku, nom, id
FROM Productes 
WHERE codi_sku > :ultim_sku 
   OR (codi_sku = :ultim_sku AND id > :ultim_id_unic)
ORDER BY codi_sku ASC, id ASC
LIMIT :limit;
```

<div _ngcontent-ng-c243700105="" class="code-block ng-tns-c243700105-344 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" id="bkmrk--11" jslog="223238;track:impression,attention;BardVeMetadataKey:[["r_e85bf8695a573c08","c_f93da456ed382884",null,"rc_6f009f4171a48282",null,null,"ca",null,1,null,null,1,0]]"><div _ngcontent-ng-c243700105="" class="formatted-code-block-internal-container ng-tns-c243700105-344"><div _ngcontent-ng-c243700105="" class="animated-opacity ng-tns-c243700105-344"></div></div></div><div _ngcontent-ng-c2268849367="" class="markdown markdown-main-panel enable-updated-hr-color" dir="ltr" id="bkmrk-com-funciona%3A-busca--1" inline-copy-host="">- **Com funciona:** Busca tots els productes on el `codi_sku` és lexicogràficament **més gran** que l'últim vist. Si hi ha SKUs idèntics, desempatarà amb l'`id` per evitar omissions.

</div>Aquest mètode és robust i trasllada l'eficiència dels índexs de BBDD a la navegació, independentment de si el teu ID principal és numèric o no.

<div _ngcontent-ng-c2268849367="" class="markdown markdown-main-panel enable-updated-hr-color" dir="ltr" id="bkmrk--12" inline-copy-host=""></div>

# Inserir dades

## MySQLi Procedural

Aquest mètode utilitza funcions prefixades amb `mysqli_` i les marques de posició (`?`).

### Inserció de dades i obtenció de l'ID

<div _ngcontent-ng-c1448405485="" class="markdown markdown-main-panel enable-updated-hr-color" dir="ltr" id="bkmrk-" inline-copy-host=""></div><div _ngcontent-ng-c2531377157="" class="code-block ng-tns-c2531377157-97 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" id="bkmrk-php" jslog="223238;track:impression,attention;BardVeMetadataKey:[["r_5a4b9f7c9bb4fd95","c_f93da456ed382884",null,"rc_c24b0ffab3af524a",null,null,"ca",null,1,null,null,1,0]]"><div _ngcontent-ng-c2531377157="" class="code-block-decoration header-formatted gds-title-s ng-tns-c2531377157-97 ng-star-inserted"><span class="ng-tns-c2531377157-97">PHP</span><div _ngcontent-ng-c2531377157="" class="buttons ng-tns-c2531377157-97 ng-star-inserted"><button aria-label="Copiar código" class="mdc-icon-button mat-mdc-icon-button mat-mdc-button-base mat-mdc-tooltip-trigger copy-button ng-tns-c2531377157-97 mat-unthemed _mat-animation-noopable ng-star-inserted"></button></div></div><div _ngcontent-ng-c2531377157="" class="formatted-code-block-internal-container ng-tns-c2531377157-97"><div _ngcontent-ng-c2531377157="" class="animated-opacity ng-tns-c2531377157-97"></div></div></div>```php
<?php
// Suposant que $conn és la connexió establerta

$nom = "Jordi";
$email = "jordi@exemple.cat";

// 1. Preparar la sentència
$stmt = mysqli_prepare($conn, "INSERT INTO Usuaris (nom, email) VALUES (?, ?)");

// 2. Vincular les variables a la sentència
// El primer paràmetre indica els tipus de dades: 's' per a string, 'i' per a integer, 'd' per a double
mysqli_stmt_bind_param($stmt, "ss", $nom, $email);

// 3. Executar la sentència
if (mysqli_stmt_execute($stmt)) {
    // 4. Obtenir l'últim ID Inserit
    $last_id = mysqli_insert_id($conn);
    echo "Nou registre creat amb èxit. ID: " . $last_id . ".\n";
} else {
    echo "Error en la inserció: " . mysqli_error($conn) . "\n";
}

// 5. Tancar el statement (i opcionalment la connexió)
mysqli_stmt_close($stmt);
// mysqli_close($conn); 
?>
```

<div _ngcontent-ng-c2531377157="" class="code-block ng-tns-c2531377157-97 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" id="bkmrk--1" jslog="223238;track:impression,attention;BardVeMetadataKey:[["r_5a4b9f7c9bb4fd95","c_f93da456ed382884",null,"rc_c24b0ffab3af524a",null,null,"ca",null,1,null,null,1,0]]"><div _ngcontent-ng-c2531377157="" class="formatted-code-block-internal-container ng-tns-c2531377157-97"><div _ngcontent-ng-c2531377157="" class="animated-opacity ng-tns-c2531377157-97"></div></div></div>## MySQLi Orientat a Objectes (OO)

Aquest mètode utilitza mètodes de l'objecte `$conn` i l'objecte `$stmt`.

### Inserció de dades i obtenció de l'ID

<div _ngcontent-ng-c1448405485="" class="markdown markdown-main-panel enable-updated-hr-color" dir="ltr" id="bkmrk--2" inline-copy-host=""></div><div _ngcontent-ng-c2531377157="" class="code-block ng-tns-c2531377157-98 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" id="bkmrk-php-1" jslog="223238;track:impression,attention;BardVeMetadataKey:[["r_5a4b9f7c9bb4fd95","c_f93da456ed382884",null,"rc_c24b0ffab3af524a",null,null,"ca",null,1,null,null,1,0]]"><div _ngcontent-ng-c2531377157="" class="code-block-decoration header-formatted gds-title-s ng-tns-c2531377157-98 ng-star-inserted"><span class="ng-tns-c2531377157-98">PHP</span><div _ngcontent-ng-c2531377157="" class="buttons ng-tns-c2531377157-98 ng-star-inserted"><button aria-label="Copiar código" class="mdc-icon-button mat-mdc-icon-button mat-mdc-button-base mat-mdc-tooltip-trigger copy-button ng-tns-c2531377157-98 mat-unthemed _mat-animation-noopable ng-star-inserted"></button></div></div><div _ngcontent-ng-c2531377157="" class="formatted-code-block-internal-container ng-tns-c2531377157-98"><div _ngcontent-ng-c2531377157="" class="animated-opacity ng-tns-c2531377157-98"></div></div></div>```php
<?php
// Suposant que $conn és l'objecte de connexió mysqli

$nom = "Anna";
$email = "anna@exemple.cat";

try {
    // 1. Preparar la sentència
    $stmt = $conn->prepare("INSERT INTO Usuaris (nom, email) VALUES (?, ?)");

    // 2. Vincular les variables a la sentència
    $stmt->bind_param("ss", $nom, $email);

    // 3. Executar la sentència
    if ($stmt->execute()) {
        // 4. Obtenir l'últim ID Inserit
        $last_id = $conn->insert_id;
        echo "Nou registre creat amb èxit. ID: " . $last_id . ".\n";
    } else {
        throw new Exception("L'execució de la consulta va fallar.");
    }
} catch (Exception $e) {
    echo "Error: " . $e->getMessage() . " (" . $conn->error . ")\n";
}

// 5. Tancar el statement (i opcionalment la connexió)
$stmt->close();
// $conn->close();
?>
```

<div _ngcontent-ng-c2531377157="" class="code-block ng-tns-c2531377157-98 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" id="bkmrk--3" jslog="223238;track:impression,attention;BardVeMetadataKey:[["r_5a4b9f7c9bb4fd95","c_f93da456ed382884",null,"rc_c24b0ffab3af524a",null,null,"ca",null,1,null,null,1,0]]"><div _ngcontent-ng-c2531377157="" class="formatted-code-block-internal-container ng-tns-c2531377157-98"><div _ngcontent-ng-c2531377157="" class="animated-opacity ng-tns-c2531377157-98"></div></div></div>## PDO (PHP Data Objects)

PDO és la forma més neta i segura. Utilitza la funció **`lastInsertId()`** directament sobre l'objecte PDO.

### Inserció de dades i obtenció de l'ID

<div _ngcontent-ng-c1448405485="" class="markdown markdown-main-panel enable-updated-hr-color" dir="ltr" id="bkmrk--4" inline-copy-host=""></div><div _ngcontent-ng-c2531377157="" class="code-block ng-tns-c2531377157-99 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" id="bkmrk-php-2" jslog="223238;track:impression,attention;BardVeMetadataKey:[["r_5a4b9f7c9bb4fd95","c_f93da456ed382884",null,"rc_c24b0ffab3af524a",null,null,"ca",null,1,null,null,1,0]]"><div _ngcontent-ng-c2531377157="" class="code-block-decoration header-formatted gds-title-s ng-tns-c2531377157-99 ng-star-inserted"><span class="ng-tns-c2531377157-99">PHP</span><div _ngcontent-ng-c2531377157="" class="buttons ng-tns-c2531377157-99 ng-star-inserted"><button aria-label="Copiar código" class="mdc-icon-button mat-mdc-icon-button mat-mdc-button-base mat-mdc-tooltip-trigger copy-button ng-tns-c2531377157-99 mat-unthemed _mat-animation-noopable ng-star-inserted"></button></div></div><div _ngcontent-ng-c2531377157="" class="formatted-code-block-internal-container ng-tns-c2531377157-99"><div _ngcontent-ng-c2531377157="" class="animated-opacity ng-tns-c2531377157-99"></div></div></div>```php
<?php
// Suposant que $pdo és l'objecte de connexió PDO
// Recordeu tenir la gestió d'errors (ERRMODE_EXCEPTION) activada al $pdo

$nom = "Marc";
$email = "marc@exemple.cat";

try {
    // 1. Preparar la sentència
    $stmt = $pdo->prepare("INSERT INTO Usuaris (nom, email) VALUES (?, ?)");

    // 2. Executar la sentència, passant les dades com un array
    // PDO determina automàticament els tipus, simplificant la vinculació
    $stmt->execute([$nom, $email]);

    // 3. Obtenir l'últim ID Inserit
    $last_id = $pdo->lastInsertId();
    echo "Nou registre creat amb èxit. ID: " . $last_id . ".\n";

} catch (PDOException $e) {
    echo "Error en la inserció: " . $e->getMessage() . ".\n";
}

// El statement es tanca automàticament en finalitzar
// $pdo = null; // Tancar connexió
?>
```

<div _ngcontent-ng-c2531377157="" class="code-block ng-tns-c2531377157-99 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" id="bkmrk--5" jslog="223238;track:impression,attention;BardVeMetadataKey:[["r_5a4b9f7c9bb4fd95","c_f93da456ed382884",null,"rc_c24b0ffab3af524a",null,null,"ca",null,1,null,null,1,0]]"><div _ngcontent-ng-c2531377157="" class="formatted-code-block-internal-container ng-tns-c2531377157-99"><div _ngcontent-ng-c2531377157="" class="animated-opacity ng-tns-c2531377157-99"></div></div></div><div _ngcontent-ng-c1448405485="" class="markdown markdown-main-panel enable-updated-hr-color" dir="ltr" id="bkmrk--6" inline-copy-host=""></div>

# Inserir dades multiples

Podem utilitzar la funció **`multi_query`** (o `mysqli_multi_query`) amb MySQLi per executar múltiples sentències SQL en una sola trucada. Aquesta és la tècnica habitual per a la inserció de *múltiples registres*. No obstant això, amb PDO i, en general, per raons de **seguretat** i **eficiència**, la manera més professional de fer múltiples insercions és utilitzar **Sentències Preparades** dins d'una **Transacció** (especialment amb PDO). A continuació, s'explica com fer-ho amb els tres mètodes.

## MySQLi Procedural: `mysqli_multi_query()`

Aquest mètode és el més directe per a consultes que **no** utilitzen dades de l'usuari (és a dir, sense risc d'injecció SQL, com en el vostre exemple).

Es concatenen totes les sentències `INSERT` separades per un punt i coma (`;`) i s'executa una sola funció.

<div _ngcontent-ng-c2268849367="" class="markdown markdown-main-panel enable-updated-hr-color" dir="ltr" id="bkmrk-" inline-copy-host=""></div><div _ngcontent-ng-c243700105="" class="code-block ng-tns-c243700105-106 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" id="bkmrk-php" jslog="223238;track:impression,attention;BardVeMetadataKey:[["r_55b2f78c995709ed","c_f93da456ed382884",null,"rc_e1f554985cbaa9cf",null,null,"ca",null,1,null,null,1,0]]"><div _ngcontent-ng-c243700105="" class="code-block-decoration header-formatted gds-title-s ng-tns-c243700105-106 ng-star-inserted"><span class="ng-tns-c243700105-106">PHP</span><div _ngcontent-ng-c243700105="" class="buttons ng-tns-c243700105-106 ng-star-inserted"><button aria-label="Copiar código" class="mdc-icon-button mat-mdc-icon-button mat-mdc-button-base mat-mdc-tooltip-trigger copy-button ng-tns-c243700105-106 mat-unthemed _mat-animation-noopable ng-star-inserted"></button></div></div><div _ngcontent-ng-c243700105="" class="formatted-code-block-internal-container ng-tns-c243700105-106"><div _ngcontent-ng-c243700105="" class="animated-opacity ng-tns-c243700105-106"></div></div></div>```php
<?php
// Suposant que $conn és la connexió establerta

$sql = "INSERT INTO MyGuests (firstname, lastname, email) VALUES ('John', 'Doe', 'john@example.com');";
$sql .= "INSERT INTO MyGuests (firstname, lastname, email) VALUES ('Mary', 'Moe', 'mary@example.com');";
$sql .= "INSERT INTO MyGuests (firstname, lastname, email) VALUES ('Julie', 'Dooley', 'julie@example.com')";

if (mysqli_multi_query($conn, $sql)) {
    echo "New records created successfully (Procedural multi_query).";
    // Nota: El codi addicional seria necessari si les consultes fossin de tipus SELECT
} else {
    echo "Error: " . mysqli_error($conn);
}

mysqli_close($conn);
?>
```

<div _ngcontent-ng-c243700105="" class="code-block ng-tns-c243700105-106 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" id="bkmrk--1" jslog="223238;track:impression,attention;BardVeMetadataKey:[["r_55b2f78c995709ed","c_f93da456ed382884",null,"rc_e1f554985cbaa9cf",null,null,"ca",null,1,null,null,1,0]]"><div _ngcontent-ng-c243700105="" class="formatted-code-block-internal-container ng-tns-c243700105-106"><div _ngcontent-ng-c243700105="" class="animated-opacity ng-tns-c243700105-106"></div></div></div><div _ngcontent-ng-c2268849367="" class="markdown markdown-main-panel enable-updated-hr-color" dir="ltr" id="bkmrk-mecanisme%3A-mysqli_mu" inline-copy-host="">- **Mecanisme:** `mysqli_multi_query()`
- **Avantatge:** Molt ràpid per a sentències fixes.
- **Inconvenient:** **Insegur** si les dades provenen d'un usuari. No gestiona bé l'obtenció d'IDs de múltiples insercions.

</div>## MySQLi Orientat a Objectes (OO): `$conn->multi_query()`

Igual que el mètode procedural, utilitza la funció nativa per executar múltiples sentències encadenades.

<div _ngcontent-ng-c2268849367="" class="markdown markdown-main-panel enable-updated-hr-color" dir="ltr" id="bkmrk--2" inline-copy-host=""></div><div _ngcontent-ng-c243700105="" class="code-block ng-tns-c243700105-107 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" id="bkmrk-php-1" jslog="223238;track:impression,attention;BardVeMetadataKey:[["r_55b2f78c995709ed","c_f93da456ed382884",null,"rc_e1f554985cbaa9cf",null,null,"ca",null,1,null,null,1,0]]"><div _ngcontent-ng-c243700105="" class="code-block-decoration header-formatted gds-title-s ng-tns-c243700105-107 ng-star-inserted"><span class="ng-tns-c243700105-107">PHP</span><div _ngcontent-ng-c243700105="" class="buttons ng-tns-c243700105-107 ng-star-inserted"><button aria-label="Copiar código" class="mdc-icon-button mat-mdc-icon-button mat-mdc-button-base mat-mdc-tooltip-trigger copy-button ng-tns-c243700105-107 mat-unthemed _mat-animation-noopable ng-star-inserted"></button></div></div><div _ngcontent-ng-c243700105="" class="formatted-code-block-internal-container ng-tns-c243700105-107"><div _ngcontent-ng-c243700105="" class="animated-opacity ng-tns-c243700105-107"></div></div></div>```php
<?php
// Suposant que $conn és l'objecte de connexió mysqli

$sql = "INSERT INTO MyGuests (firstname, lastname, email) VALUES ('John', 'Doe', 'john@example.com');";
$sql .= "INSERT INTO MyGuests (firstname, lastname, email) VALUES ('Mary', 'Moe', 'mary@example.com');";
$sql .= "INSERT INTO MyGuests (firstname, lastname, email) VALUES ('Julie', 'Dooley', 'julie@example.com')";

if ($conn->multi_query($sql) === TRUE) {
    echo "New records created successfully (OO multi_query).";
} else {
    echo "Error: " . $conn->error;
}

$conn->close();
?>
```

<div _ngcontent-ng-c243700105="" class="code-block ng-tns-c243700105-107 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" id="bkmrk--3" jslog="223238;track:impression,attention;BardVeMetadataKey:[["r_55b2f78c995709ed","c_f93da456ed382884",null,"rc_e1f554985cbaa9cf",null,null,"ca",null,1,null,null,1,0]]"><div _ngcontent-ng-c243700105="" class="formatted-code-block-internal-container ng-tns-c243700105-107"><div _ngcontent-ng-c243700105="" class="animated-opacity ng-tns-c243700105-107"></div></div></div><div _ngcontent-ng-c2268849367="" class="markdown markdown-main-panel enable-updated-hr-color" dir="ltr" id="bkmrk-mecanisme%3A-%24conn-%3Emu" inline-copy-host="">- **Mecanisme:** `$conn->multi_query($sql)`
- **Avantatge/Inconvenient:** Igual que el procedural.

</div>## PDO: Sentències preparades i transaccions (Recomanat)

Aquesta és la manera **més segura i controlada**. Es prepara una sola sentència `INSERT` i s'executa repetidament dins d'una **transacció**. Una transacció garanteix que, o bé **totes** les insercions es completen (`commit`), o bé **cap** no es fa (`rollback`) si alguna falla.

### Inserció múltiple i segura

<div _ngcontent-ng-c2268849367="" class="markdown markdown-main-panel enable-updated-hr-color" dir="ltr" id="bkmrk--4" inline-copy-host=""></div><div _ngcontent-ng-c243700105="" class="code-block ng-tns-c243700105-108 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" id="bkmrk-php-2" jslog="223238;track:impression,attention;BardVeMetadataKey:[["r_55b2f78c995709ed","c_f93da456ed382884",null,"rc_e1f554985cbaa9cf",null,null,"ca",null,1,null,null,1,0]]"><div _ngcontent-ng-c243700105="" class="code-block-decoration header-formatted gds-title-s ng-tns-c243700105-108 ng-star-inserted"><span class="ng-tns-c243700105-108">PHP</span><div _ngcontent-ng-c243700105="" class="buttons ng-tns-c243700105-108 ng-star-inserted"><button aria-label="Copiar código" class="mdc-icon-button mat-mdc-icon-button mat-mdc-button-base mat-mdc-tooltip-trigger copy-button ng-tns-c243700105-108 mat-unthemed _mat-animation-noopable ng-star-inserted"></button></div></div><div _ngcontent-ng-c243700105="" class="formatted-code-block-internal-container ng-tns-c243700105-108"><div _ngcontent-ng-c243700105="" class="animated-opacity ng-tns-c243700105-108"></div></div></div>```php
<?php
// Suposant que $pdo és l'objecte de connexió PDO

$dades = [
    ['John', 'Doe', 'john@example.com'],
    ['Mary', 'Moe', 'mary@example.com'],
    ['Julie', 'Dooley', 'julie@example.com']
];

$sql = "INSERT INTO MyGuests (firstname, lastname, email) VALUES (?, ?, ?)";

try {
    $pdo->beginTransaction(); // 1. Iniciar la Transacció
    $stmt = $pdo->prepare($sql); // 2. Preparar la Sentència (només una vegada)
    $comptador = 0;

    foreach ($dades as $registre) {
        $stmt->execute($registre); // 3. Executar la Sentència per cada registre
        $comptador++;
        // NOTA: Per obtenir IDs individuals, s'hauria de cridar $pdo->lastInsertId() dins del bucle
    }

    $pdo->commit(); // 4. Confirmar els canvis
    echo "New records created successfully ($comptador insercions via PDO Transaction).";

} catch (PDOException $e) {
    $pdo->rollBack(); // 5. Desfer els canvis si alguna cosa ha fallat
    echo "Error en la transacció: " . $e->getMessage();
}

$pdo = null; // Tancar connexió
?>

```

<div _ngcontent-ng-c243700105="" class="code-block ng-tns-c243700105-108 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" id="bkmrk--5" jslog="223238;track:impression,attention;BardVeMetadataKey:[["r_55b2f78c995709ed","c_f93da456ed382884",null,"rc_e1f554985cbaa9cf",null,null,"ca",null,1,null,null,1,0]]"><div _ngcontent-ng-c243700105="" class="formatted-code-block-internal-container ng-tns-c243700105-108"><div _ngcontent-ng-c243700105="" class="animated-opacity ng-tns-c243700105-108"></div></div></div><div _ngcontent-ng-c2268849367="" class="markdown markdown-main-panel enable-updated-hr-color" dir="ltr" id="bkmrk-mecanisme%3A-transacci" inline-copy-host="">- **Mecanisme:** Transaccions (`beginTransaction`, `commit`, `rollBack`) amb Sentències Preparades (`prepare`, `execute`).
- **Avantatge:** **Màxima seguretat** (contra SQL Injection) i **Integritat de dades** (Atomicidad: totes o cap).
- **Eficiència:** Preparar la sentència només una vegada i executar-la múltiples vegades és molt ràpid.

</div>

# Delete data

Per eliminar un registre d'una taula, farem servir la sentència **`DELETE FROM`** de SQL. Igual que amb les altres operacions que involucren dades de l'usuari (en aquest cas, l'ID del registre a eliminar), utilitzarem **Sentències preparades** per evitar l'atac de la Injecció SQL.

Aquí teniu com implementar l'eliminació amb **MySQLi Procedural**, **MySQLi OO** i **PDO**.

## MySQLi Procedural

Aquest mètode utilitza la funció `mysqli_prepare()` i l'enllaç de connexió.

### Eliminació del registre

<div _ngcontent-ng-c2268849367="" class="markdown markdown-main-panel enable-updated-hr-color" dir="ltr" id="bkmrk-" inline-copy-host=""></div><div _ngcontent-ng-c243700105="" class="code-block ng-tns-c243700105-232 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" id="bkmrk-php" jslog="223238;track:impression,attention;BardVeMetadataKey:[["r_f30ee86c60c3ee53","c_f93da456ed382884",null,"rc_9e90cfb6b92791ef",null,null,"ca",null,1,null,null,1,0]]"><div _ngcontent-ng-c243700105="" class="code-block-decoration header-formatted gds-title-s ng-tns-c243700105-232 ng-star-inserted"><span class="ng-tns-c243700105-232">PHP</span><div _ngcontent-ng-c243700105="" class="buttons ng-tns-c243700105-232 ng-star-inserted"><button aria-label="Copiar código" class="mdc-icon-button mat-mdc-icon-button mat-mdc-button-base mat-mdc-tooltip-trigger copy-button ng-tns-c243700105-232 mat-unthemed _mat-animation-noopable ng-star-inserted"></button></div></div><div _ngcontent-ng-c243700105="" class="formatted-code-block-internal-container ng-tns-c243700105-232"><div _ngcontent-ng-c243700105="" class="animated-opacity ng-tns-c243700105-232"></div></div></div>```php
<?php
// Suposant que $conn és la connexió establerta
$id_a_eliminar = 5; // ID del registre que volem eliminar

// 1. Preparar la sentència DELETE
$sql = "DELETE FROM Usuaris WHERE id = ?";
$stmt = mysqli_prepare($conn, $sql);

// 2. Vincular el paràmetre (la ID és un enter: 'i')
mysqli_stmt_bind_param($stmt, "i", $id_a_eliminar);

// 3. Executar la sentència
if (mysqli_stmt_execute($stmt)) {
    // 4. Comprovar si s'ha eliminat alguna fila
    if (mysqli_stmt_affected_rows($stmt) > 0) {
        echo "Registre amb ID " . $id_a_eliminar . " eliminat amb èxit (Procedural). \n";
    } else {
        echo "No s'ha trobat cap registre amb ID " . $id_a_eliminar . " per eliminar.\n";
    }
} else {
    echo "Error en l'execució: " . mysqli_error($conn) . "\n";
}

// 5. Tancar el statement
mysqli_stmt_close($stmt);
// mysqli_close($conn); 
?>
```

<div _ngcontent-ng-c243700105="" class="code-block ng-tns-c243700105-232 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" id="bkmrk--1" jslog="223238;track:impression,attention;BardVeMetadataKey:[["r_f30ee86c60c3ee53","c_f93da456ed382884",null,"rc_9e90cfb6b92791ef",null,null,"ca",null,1,null,null,1,0]]"><div _ngcontent-ng-c243700105="" class="formatted-code-block-internal-container ng-tns-c243700105-232"><div _ngcontent-ng-c243700105="" class="animated-opacity ng-tns-c243700105-232"></div></div></div>## MySQLi Orientat a Objectes (OO)

Aquest mètode utilitza el mètode `prepare()` de l'objecte `$conn`.

### Eliminació del registre

<div _ngcontent-ng-c2268849367="" class="markdown markdown-main-panel enable-updated-hr-color" dir="ltr" id="bkmrk--2" inline-copy-host=""></div><div _ngcontent-ng-c243700105="" class="code-block ng-tns-c243700105-233 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" id="bkmrk-php-1" jslog="223238;track:impression,attention;BardVeMetadataKey:[["r_f30ee86c60c3ee53","c_f93da456ed382884",null,"rc_9e90cfb6b92791ef",null,null,"ca",null,1,null,null,1,0]]"><div _ngcontent-ng-c243700105="" class="code-block-decoration header-formatted gds-title-s ng-tns-c243700105-233 ng-star-inserted"><span class="ng-tns-c243700105-233">PHP</span><div _ngcontent-ng-c243700105="" class="buttons ng-tns-c243700105-233 ng-star-inserted"><button aria-label="Copiar código" class="mdc-icon-button mat-mdc-icon-button mat-mdc-button-base mat-mdc-tooltip-trigger copy-button ng-tns-c243700105-233 mat-unthemed _mat-animation-noopable ng-star-inserted"></button></div></div><div _ngcontent-ng-c243700105="" class="formatted-code-block-internal-container ng-tns-c243700105-233"><div _ngcontent-ng-c243700105="" class="animated-opacity ng-tns-c243700105-233"></div></div></div>```php
<?php
// Suposant que $conn és l'objecte de connexió mysqli
$id_a_eliminar = 6;

try {
    // 1. Preparar la sentència DELETE
    $stmt = $conn->prepare("DELETE FROM Usuaris WHERE id = ?");

    // 2. Vincular el paràmetre (la ID és un enter: 'i')
    $stmt->bind_param("i", $id_a_eliminar);

    // 3. Executar la sentència
    if ($stmt->execute()) {
        // 4. Comprovar si s'ha eliminat alguna fila
        if ($stmt->affected_rows > 0) {
            echo "Registre amb ID " . $id_a_eliminar . " eliminat amb èxit (OO). \n";
        } else {
            echo "No s'ha trobat cap registre amb ID " . $id_a_eliminar . " per eliminar.\n";
        }
    } else {
        throw new Exception("L'execució de la consulta va fallar.");
    }
} catch (Exception $e) {
    echo "Error: " . $e->getMessage() . " (" . $conn->error . ")\n";
}

// 5. Tancar el statement
$stmt->close();
// $conn->close();
?>
```

<div _ngcontent-ng-c243700105="" class="code-block ng-tns-c243700105-233 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" id="bkmrk--3" jslog="223238;track:impression,attention;BardVeMetadataKey:[["r_f30ee86c60c3ee53","c_f93da456ed382884",null,"rc_9e90cfb6b92791ef",null,null,"ca",null,1,null,null,1,0]]"><div _ngcontent-ng-c243700105="" class="formatted-code-block-internal-container ng-tns-c243700105-233"><div _ngcontent-ng-c243700105="" class="animated-opacity ng-tns-c243700105-233"></div></div></div>## PDO (PHP Data Objects)

PDO és el mètode més net, utilitzant **`execute()`** amb un *array* de dades.

### Eliminació del registre

<div _ngcontent-ng-c2268849367="" class="markdown markdown-main-panel enable-updated-hr-color" dir="ltr" id="bkmrk--4" inline-copy-host=""></div><div _ngcontent-ng-c243700105="" class="code-block ng-tns-c243700105-234 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" id="bkmrk-php-2" jslog="223238;track:impression,attention;BardVeMetadataKey:[["r_f30ee86c60c3ee53","c_f93da456ed382884",null,"rc_9e90cfb6b92791ef",null,null,"ca",null,1,null,null,1,0]]"><div _ngcontent-ng-c243700105="" class="code-block-decoration header-formatted gds-title-s ng-tns-c243700105-234 ng-star-inserted"><span class="ng-tns-c243700105-234">PHP</span><div _ngcontent-ng-c243700105="" class="buttons ng-tns-c243700105-234 ng-star-inserted"><button aria-label="Copiar código" class="mdc-icon-button mat-mdc-icon-button mat-mdc-button-base mat-mdc-tooltip-trigger copy-button ng-tns-c243700105-234 mat-unthemed _mat-animation-noopable ng-star-inserted"></button></div></div><div _ngcontent-ng-c243700105="" class="formatted-code-block-internal-container ng-tns-c243700105-234"><div _ngcontent-ng-c243700105="" class="animated-opacity ng-tns-c243700105-234"></div></div></div>```php
<?php
// Suposant que $pdo és l'objecte de connexió PDO
$id_a_eliminar = 7;

try {
    // 1. Preparar la sentència DELETE
    $sql = "DELETE FROM Usuaris WHERE id = ?";
    $stmt = $pdo->prepare($sql);

    // 2. Executar la sentència, passant la ID com a array
    $stmt->execute([$id_a_eliminar]);

    // 3. Comprovar si s'ha eliminat alguna fila
    // s'utilitza rowCount() directament sobre el statement
    if ($stmt->rowCount() > 0) {
        echo "Registre amb ID " . $id_a_eliminar . " eliminat amb èxit (PDO). \n";
    } else {
        echo "No s'ha trobat cap registre amb ID " . $id_a_eliminar . " per eliminar.\n";
    }

} catch (PDOException $e) {
    die("Error en l'eliminació: " . $e->getMessage() . ".\n");
}

// 4. Tancar
// $pdo = null; // Tancar connexió
?>
```

<div _ngcontent-ng-c243700105="" class="code-block ng-tns-c243700105-234 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" id="bkmrk--5" jslog="223238;track:impression,attention;BardVeMetadataKey:[["r_f30ee86c60c3ee53","c_f93da456ed382884",null,"rc_9e90cfb6b92791ef",null,null,"ca",null,1,null,null,1,0]]"><div _ngcontent-ng-c243700105="" class="formatted-code-block-internal-container ng-tns-c243700105-234"><div _ngcontent-ng-c243700105="" class="animated-opacity ng-tns-c243700105-234"></div></div></div><div _ngcontent-ng-c2268849367="" class="markdown markdown-main-panel enable-updated-hr-color" dir="ltr" id="bkmrk--6" inline-copy-host=""></div>### Com comprovar-ho?

Per confirmar que s'ha eliminat un registre, en lloc de comprovar l'èxit de l'execució (`true`), el que es comprova és el nombre de files afectades:

<div _ngcontent-ng-c2268849367="" class="markdown markdown-main-panel enable-updated-hr-color" dir="ltr" id="bkmrk-mysqli-%28oo%29%3A-%24stmt-%3E" inline-copy-host="">- **MySQLi (OO):** `$stmt->affected_rows`
- **MySQLi (Procedural):** `mysqli_stmt_affected_rows($stmt)`
- **PDO:** `$stmt->rowCount()`

</div>Si el valor retornat és **major que 0**, vol dir que s'ha eliminat un o més registres. Si és 0, la consulta ha funcionat, però el registre amb aquesta `ID` no existia.

<div _ngcontent-ng-c2268849367="" class="markdown markdown-main-panel enable-updated-hr-color" dir="ltr" id="bkmrk--7" inline-copy-host=""></div>

# Update data

Per actualitzar un registre existent a una taula, s'utilitza la sentència **`UPDATE`** de SQL, especificant els camps i valors nous i utilitzant una clàusula **`WHERE`** per identificar el registre concret a modificar (normalment per la seva ID). Com en totes les operacions amb dades d'usuari, és crucial utilitzar **Sentències preparades** per prevenir la Injecció SQL.

## MySQLi Procedural

Aquest mètode utilitza la funció `mysqli_prepare()` i l'enllaç de connexió.

### Actualització registre

<div _ngcontent-ng-c2268849367="" class="markdown markdown-main-panel enable-updated-hr-color" dir="ltr" id="bkmrk-" inline-copy-host=""></div><div _ngcontent-ng-c243700105="" class="code-block ng-tns-c243700105-249 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" id="bkmrk-php" jslog="223238;track:impression,attention;BardVeMetadataKey:[["r_44ea539e2ecdf0ee","c_f93da456ed382884",null,"rc_6769ecda7580cc3e",null,null,"ca",null,1,null,null,1,0]]"><div _ngcontent-ng-c243700105="" class="code-block-decoration header-formatted gds-title-s ng-tns-c243700105-249 ng-star-inserted"><span class="ng-tns-c243700105-249">PHP</span><div _ngcontent-ng-c243700105="" class="buttons ng-tns-c243700105-249 ng-star-inserted"><button aria-label="Copiar código" class="mdc-icon-button mat-mdc-icon-button mat-mdc-button-base mat-mdc-tooltip-trigger copy-button ng-tns-c243700105-249 mat-unthemed _mat-animation-noopable ng-star-inserted"></button></div></div><div _ngcontent-ng-c243700105="" class="formatted-code-block-internal-container ng-tns-c243700105-249"><div _ngcontent-ng-c243700105="" class="animated-opacity ng-tns-c243700105-249"></div></div></div>```php
<?php
// Suposant que $conn és la connexió establerta

$nou_nom = "Carla López";
$nou_email = "carla.lopez@nova.cat";
$id_a_actualitzar = 8; 

// 1. Preparar la sentència UPDATE amb marcadors de posició (?)
$sql = "UPDATE Usuaris SET nom = ?, email = ? WHERE id = ?";
$stmt = mysqli_prepare($conn, $sql);

// 2. Vincular els paràmetres
// Tipus: "ssi" (dos strings i un integer)
mysqli_stmt_bind_param($stmt, "ssi", $nou_nom, $nou_email, $id_a_actualitzar);

// 3. Executar la sentència
if (mysqli_stmt_execute($stmt)) {
    // 4. Comprovar si s'ha actualitzat alguna fila
    if (mysqli_stmt_affected_rows($stmt) > 0) {
        echo "Registre amb ID " . $id_a_actualitzar . " actualitzat amb èxit (Procedural). \n";
    } else {
        echo "No s'ha fet cap canvi (el registre no existeix o les dades són les mateixes).\n";
    }
} else {
    echo "Error en l'execució: " . mysqli_error($conn) . "\n";
}

// 5. Tancar el statement
mysqli_stmt_close($stmt);
// mysqli_close($conn); 
?>
```

<div _ngcontent-ng-c243700105="" class="code-block ng-tns-c243700105-249 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" id="bkmrk--1" jslog="223238;track:impression,attention;BardVeMetadataKey:[["r_44ea539e2ecdf0ee","c_f93da456ed382884",null,"rc_6769ecda7580cc3e",null,null,"ca",null,1,null,null,1,0]]"><div _ngcontent-ng-c243700105="" class="formatted-code-block-internal-container ng-tns-c243700105-249"><div _ngcontent-ng-c243700105="" class="animated-opacity ng-tns-c243700105-249"></div></div></div>## MySQLi Orientat a Objectes (OO)

Aquest mètode utilitza el mètode `prepare()` de l'objecte `$conn`.

### Actualització registre

<div _ngcontent-ng-c2268849367="" class="markdown markdown-main-panel enable-updated-hr-color" dir="ltr" id="bkmrk--2" inline-copy-host=""></div><div _ngcontent-ng-c243700105="" class="code-block ng-tns-c243700105-250 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" id="bkmrk-php-1" jslog="223238;track:impression,attention;BardVeMetadataKey:[["r_44ea539e2ecdf0ee","c_f93da456ed382884",null,"rc_6769ecda7580cc3e",null,null,"ca",null,1,null,null,1,0]]"><div _ngcontent-ng-c243700105="" class="code-block-decoration header-formatted gds-title-s ng-tns-c243700105-250 ng-star-inserted"><span class="ng-tns-c243700105-250">PHP</span><div _ngcontent-ng-c243700105="" class="buttons ng-tns-c243700105-250 ng-star-inserted"><button aria-label="Copiar código" class="mdc-icon-button mat-mdc-icon-button mat-mdc-button-base mat-mdc-tooltip-trigger copy-button ng-tns-c243700105-250 mat-unthemed _mat-animation-noopable ng-star-inserted"></button></div></div><div _ngcontent-ng-c243700105="" class="formatted-code-block-internal-container ng-tns-c243700105-250"><div _ngcontent-ng-c243700105="" class="animated-opacity ng-tns-c243700105-250"></div></div></div>```php
<?php
// Suposant que $conn és l'objecte de connexió mysqli
$nou_nom = "Toni G.";
$nou_email = "toni.g@nova.cat";
$id_a_actualitzar = 9;

try {
    // 1. Preparar la sentència UPDATE
    $stmt = $conn->prepare("UPDATE Usuaris SET nom = ?, email = ? WHERE id = ?");

    // 2. Vincular els paràmetres (ssi)
    $stmt->bind_param("ssi", $nou_nom, $nou_email, $id_a_actualitzar);

    // 3. Executar la sentència
    if ($stmt->execute()) {
        // 4. Comprovar si s'ha actualitzat alguna fila
        if ($stmt->affected_rows > 0) {
            echo "Registre amb ID " . $id_a_actualitzar . " actualitzat amb èxit (OO). \n";
        } else {
            echo "No s'ha fet cap canvi (el registre no existeix o les dades són les mateixes).\n";
        }
    } else {
        throw new Exception("L'execució de la consulta va fallar.");
    }
} catch (Exception $e) {
    echo "Error: " . $e->getMessage() . " (" . $conn->error . ")\n";
}

// 5. Tancar el statement
$stmt->close();
// $conn->close();
?>
```

<div _ngcontent-ng-c243700105="" class="code-block ng-tns-c243700105-250 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" id="bkmrk--3" jslog="223238;track:impression,attention;BardVeMetadataKey:[["r_44ea539e2ecdf0ee","c_f93da456ed382884",null,"rc_6769ecda7580cc3e",null,null,"ca",null,1,null,null,1,0]]"><div _ngcontent-ng-c243700105="" class="formatted-code-block-internal-container ng-tns-c243700105-250"><div _ngcontent-ng-c243700105="" class="animated-opacity ng-tns-c243700105-250"></div></div></div>## PDO (PHP Data Objects)

PDO és el mètode més concís i prefereix l'execució amb un *array* de dades.

### Actualització registre

<div _ngcontent-ng-c2268849367="" class="markdown markdown-main-panel enable-updated-hr-color" dir="ltr" id="bkmrk--4" inline-copy-host=""></div><div _ngcontent-ng-c243700105="" class="code-block ng-tns-c243700105-251 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" id="bkmrk-php-2" jslog="223238;track:impression,attention;BardVeMetadataKey:[["r_44ea539e2ecdf0ee","c_f93da456ed382884",null,"rc_6769ecda7580cc3e",null,null,"ca",null,1,null,null,1,0]]"><div _ngcontent-ng-c243700105="" class="code-block-decoration header-formatted gds-title-s ng-tns-c243700105-251 ng-star-inserted"><span class="ng-tns-c243700105-251">PHP</span><div _ngcontent-ng-c243700105="" class="buttons ng-tns-c243700105-251 ng-star-inserted"><button aria-label="Copiar código" class="mdc-icon-button mat-mdc-icon-button mat-mdc-button-base mat-mdc-tooltip-trigger copy-button ng-tns-c243700105-251 mat-unthemed _mat-animation-noopable ng-star-inserted"></button></div></div><div _ngcontent-ng-c243700105="" class="formatted-code-block-internal-container ng-tns-c243700105-251"><div _ngcontent-ng-c243700105="" class="animated-opacity ng-tns-c243700105-251"></div></div></div>```php
<?php
// Suposant que $pdo és l'objecte de connexió PDO
$nou_nom = "Marta Riera";
$nou_email = "marta.riera@nova.cat";
$id_a_actualitzar = 10;

// NOTA: Amb PDO, l'ordre de les dades a l'array d'execució ha de coincidir amb l'ordre dels '?'
try {
    // 1. Preparar la sentència UPDATE
    $sql = "UPDATE Usuaris SET nom = ?, email = ? WHERE id = ?";
    $stmt = $pdo->prepare($sql);

    // 2. Executar la sentència, passant totes les dades en un array
    $stmt->execute([$nou_nom, $nou_email, $id_a_actualitzar]);

    // 3. Comprovar si s'ha actualitzat alguna fila
    if ($stmt->rowCount() > 0) {
        echo "Registre amb ID " . $id_a_actualitzar . " actualitzat amb èxit (PDO). ✅\n";
    } else {
        echo "No s'ha fet cap canvi (el registre no existeix o les dades són les mateixes).\n";
    }

} catch (PDOException $e) {
    die("Error en l'actualització: " . $e->getMessage() . ".\n");
}

// 4. Tancar
// $pdo = null; // Tancar connexió
?>
```

<div _ngcontent-ng-c243700105="" class="code-block ng-tns-c243700105-251 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" id="bkmrk--5" jslog="223238;track:impression,attention;BardVeMetadataKey:[["r_44ea539e2ecdf0ee","c_f93da456ed382884",null,"rc_6769ecda7580cc3e",null,null,"ca",null,1,null,null,1,0]]"><div _ngcontent-ng-c243700105="" class="formatted-code-block-internal-container ng-tns-c243700105-251"><div _ngcontent-ng-c243700105="" class="animated-opacity ng-tns-c243700105-251"></div></div></div><div _ngcontent-ng-c2268849367="" class="markdown markdown-main-panel enable-updated-hr-color" dir="ltr" id="bkmrk--6" inline-copy-host=""></div>### Com ho comprovem?

En els tres mètodes, la clau per saber si l'actualització ha tingut lloc és utilitzar la funció que retorna el **nombre de files afectades**:

<div _ngcontent-ng-c2268849367="" class="markdown markdown-main-panel enable-updated-hr-color" dir="ltr" id="bkmrk-mysqli-%28oo%29%3A-%24stmt-%3E" inline-copy-host="">- **MySQLi (OO):** `$stmt->affected_rows`
- **MySQLi (Procedural):** `mysqli_stmt_affected_rows($stmt)`
- **PDO:** `$stmt->rowCount()`

</div>Si el valor retornat és **major que 0**, s'ha fet l'actualització. Si és 0, potser la fila ja tenia els mateixos valors o la `WHERE` no va trobar cap registre.

<div _ngcontent-ng-c2268849367="" class="markdown markdown-main-panel enable-updated-hr-color" dir="ltr" id="bkmrk--7" inline-copy-host=""></div>