Workshop SQL Woensdag 16 mei 2018
Introductie Mike Winkel Martin Treur SAP B1 tips - www.linkedin.com/today/author/0_392wxhl6i7tlezhuwsgxfx?trk=prof-sm Kennisbank Serac.nl - https://www.serac.nl/kennisbank/276
Agenda Wat is een database? SAP Business One database Wat is SQL? Theorie + Oefeningen Query s Performance / Algemene Query tips MSSQL vs HANA Query s visualiseren Tips voor zelfstudie Aan de slag met eigen Query s / Vragen
Wat is een database? Gestructureerde gegevensverzameling Bestaat uit TABELLEN TABELLEN bevatten KOLOMMEN en RIJEN KOLOMMEN hebben EIGENSCHAPPEN RIJEN bevatten VELDEN VELDEN bevatten WAARDEN
Tabellen in SAP Business One database Namen van SBO-standaardtabellen hebben (meestal) vier karakters Hoofdtabellen beginnen met de letter O OINV - Facturen OITM - Artikelen OCRD - Zakenpartners Afgeleide tabellen beginnen met de laatste 3 karakters van de hoofdtabel plus een volgnummer INV1 - Factuurregels RDR1 Orderregels ITM1 Artikel prijzen Archieftabellen beginnen met een A Gebruikerstabellen en tabellen t.b.v. addons beginnen met een @
Type velden in SAP Business One database Tekst / Strings char(n) String veld met vaste lengte Max 8000 karakters nvarchar(n) Unicode String veld met variabele lengte Max 4000 karakters ntext Unicode String veld met variabele lengte Max 2GB text data Numeriek int Gehele getallen tussen -2147483648 en 2147483647 smallint Gehele getallen tussen -32768 en 32767 numeric(19, 6) Getal met maximaal 6 cijfers na de komma, totaal 19 cijfers Datums datetime date Datum + tijdstip Datum Een database kan uit nog veel meer type velden bestaan Bovenstaande velden zijn het meest gebruikt in SAP Business One Type veld bepaald welke waarde een veld kan hebben
Velden en tabellen achterhalen in SAP Business One De artikeltabel heet OITM. (ITM is van item) De factuurtabel heet OINV. (INV is van invoice) De zakenpartnertabel heet OCRD (CRD is van card) Hulpmiddelen om tabel en veldnamen te achterhalen: Systeem informatie http://www.saptables.net/
Tabellen en velden opzoeken in SAP Business One Tabel- en veldnaam zichtbaar maken via View Systeeminformatie Control + Shift + I
Wat is SQL? Structured Query Language Gestructureerde Informatie Taal Verschillende query types: SELECT query UPDATE query INSERT query DELETE query Met Query s kan je dus informatie ophalen uit een database, informatie wegschrijven, maar ook informatie aanpassen/verwijderen!
SELECT Query s Vandaag alleen de SELECT Query Ophalen van gegevens uit database Met een SELECT query geen gevaar voor overschrijven of verwijderen van gegevens
Opbouw SQL Query SELECT FROM INNER JOIN ON = WHERE.. = AND.. =.. OR.. <> GROUP BY HAVING.. ORDER BY
Voorbeeld SELECT Query SELECT CardCode, CardName FROM OCRD WHERE CardCode = 'C23900' SELECT (verplicht) Welke velden moeten getoond worden FROM ( verplicht ) Uit welke tabel(len) komen de velden WHERE (optioneel) Aan welke voorwaarden moeten de resultaten voldoen
Tabellen combineren INNER JOIN Voorbeeld: SELECT T0.CardCode, T0.CardName, T1.DocNum, T1.DocTotal FROM OCRD T0 INNER JOIN OQUT T1 on T0.CardCode = T1.CardCode OCRD CardCode CardName K0001 Klant 1 K0002 Klant 2 K0003 Klant 3 K0004 Klant 4 K0005 Klant 5 OQUT DocNum DocTotal CardCode 500001 250 K0001 500002 358 K0003 500003 145 K0001 500004 250 K0001 500005 200 K0004 500006 150 K0004 500007 350 K0001 Resultaat CardCode CardName DocNum DocTotal K0001 Klant 1 500001 250 K0001 Klant 1 500003 145 K0001 Klant 1 500004 250 K0001 Klant 1 500007 350 K0003 Klant 3 500002 358 K0004 Klant 4 500005 200 K0004 Klant 4 500006 150 INNER JOIN haalt alleen resultaten op die in BEIDE tabellen voorkomen
OPDRACHT Maak een Query van alle artikelen met: Artikelcode, Artikelomschrijving, Artikelgroep code, Artikelgroep naam Antwoord: SELECT T0.ItemCode, T0.ItemName, T1.ItmsGrpCod, T1.ItmsGrpNam FROM OITM T0 INNER JOIN OITB T1 on T0.ItmsGrpCod = T1.ItmsGrpCod
Tabellen combineren LEFT JOIN Voorbeeld: SELECT T0.CardCode, T0.CardName, T1.DocNum, T1.DocTotal FROM OCRD T0 LEFT JOIN OQUT T1 on T0.CardCode = T1.CardCode OCRD CardCode CardName K0001 Klant 1 K0002 Klant 2 K0003 Klant 3 K0004 Klant 4 K0005 Klant 5 OQUT DocNum DocTotal CardCode 500001 250 K0001 500002 358 K0003 500003 145 K0001 500004 250 K0001 500005 200 K0004 500006 150 K0004 500007 350 K0001 Resultaat CardCode CardName DocNum DocTotal K0001 Klant 1 500001 250 K0001 Klant 1 500003 145 K0001 Klant 1 500004 250 K0001 Klant 1 500007 350 K0002 Klant 2 K0003 Klant 3 500002 358 K0004 Klant 4 500005 200 K0004 Klant 4 500006 150 K0005 Klant 5 LEFT JOIN haalt alle resultaten op uit de linker tabel
OPDRACHT Maak een Query van alle artikelen met: Artikelcode, Artikelomschrijving, Hoofdleverancier code, Hoofdleverancier naam Antwoord: SELECT T0.ItemCode, T0.ItemName, T1.CardCode, T1.CardName FROM OITM T0 LEFT JOIN OCRD T1 on T0.CardCode = T1.CardCode LEFT JOIN want niet alle artikelen hebben verplicht een hoofdleverancier
Tabellen combineren CROSS JOIN Voorbeeld: SELECT t0.acctcode, t0.acctname, T1.OcrCode, T1.OcrName FROM OACT T0 CROSS JOIN OOCR T1 ORDER BY t0.acctcode OACT AcctCode AcctName 1050Grootboekrekening A 1051Grootboekrekening B 1052Grootboekrekening C OOCR OcrCode OcrName 1000 Administratie 1001 Verkoop Resultaat AcctCode AcctName OcrCode OcrName 1050 Grootboekrekening A 1000 Administratie 1050 Grootboekrekening A 1001 Verkoop 1051 Grootboekrekening B 1000 Administratie 1051 Grootboekrekening B 1001 Verkoop 1052 Grootboekrekening C 1000 Administratie 1052 Grootboekrekening C 1001 Verkoop CROSS JOIN haalt alle combinaties op uit de linker tabel en rechter tabel
Tabellen combineren Overzicht JOINS
WHERE Voorbeeld: SELECT T0.CardCode, T0.CardName, T1.DocNum, T1.DocTotal FROM OCRD T0 INNER JOIN OQUT T1 on T0.CardCode = T1.CardCode WHERE T1.DocTotal > 200 OCRD CardCode CardName K0001 Klant 1 K0002 Klant 2 K0003 Klant 3 K0004 Klant 4 K0005 Klant 5 OQUT DocNum DocTotal CardCode 500001 250K0001 500002 358K0003 500003 145K0001 500004 250K0001 500005 200K0004 500006 150K0004 500007 350K0001 Resultaat CardCode CardName DocNum DocTotal K0001 Klant 1 500001 250 K0001 Klant 1 500004 250 K0001 Klant 1 500007 350 K0003 Klant 3 500002 358 In de WHERE kan je voorwaarden zetten (filteren)
WHERE voorbeelden voorwaarden Gelijk aan - = Groter dan - > Kleiner dan - < Groter dan / gelijk aan - >= Kleiner dan / gelijk aan - <= Ongelijk - <> Bevat - Like '%_%' Bevat niet - NOT Like '%%_%%' Start met - Like '_%%' Eindigt met - Like '%%_' IS NULL - IS NULL IS NOT NULL - IS NOT NULL Komt voor in - IN ('_','_','_') Voorwaarden ook te combineren met: En - AND Of - OR
OPDRACHT Maak een Query van alle klanten en contactpersonen met: Klantnaam, Naam contactpersoon, Telefoonnummer CP, Emailadres CP. Klanten tot en met de letter M Waar Emailadres of Telefoonnummer leeg is Antwoord: SELECT T0.CardCode, T0.CardName, T1.Name, T1.Tel1, T1.E_MailL FROM OCRD T0 LEFT JOIN OCPR T1 on T0.CardCode = T1.CardCode WHERE T0.CardName <= 'N' AND (T1.E_MailL IS NULL OR T1.Tel1 IS NULL) order by 2 LEFT JOIN want niet alle klanten hebben een contactpersoon Voorbeeld AND en OR gebruik. Denk bij gebruik aan OR aan de ()
WHERE opnemen in de JOIN Voorbeeld: SELECT T0.CardCode, T0.CardName, T1.DocNum, T1.DocTotal FROM OCRD T0 INNER JOIN OQUT T1 on T0.CardCode = T1.CardCode AND T1.DocTotal > 200 OCRD CardCode CardName K0001 Klant 1 K0002 Klant 2 K0003 Klant 3 K0004 Klant 4 K0005 Klant 5 OQUT DocNum DocTotal CardCode 500001 250K0001 500002 358K0003 500003 145K0001 500004 250K0001 500005 200K0004 500006 150K0004 500007 350K0001 Resultaat CardCode CardName DocNum DocTotal K0001 Klant 1 500001 250 K0001 Klant 1 500004 250 K0001 Klant 1 500007 350 K0003 Klant 3 500002 358 Je kunt de WHERE ook direct opnemen in de JOIN
OPDRACHT Maak een Query van alle artikelen met: Artikelcode, Artikelomschrijving, Inkoopprijs, Bruto verkoopprijs Antwoord: SELECT T0.ItemCode, T0.ItemName, T1.Price as 'Inkoopprijs', T2.Price as 'Verkoopprijs' FROM OITM T0 LEFT JOIN ITM1 T1 on T0.ItemCode = T1.ItemCode AND T1.PriceList = 1 LEFT JOIN ITM1 T2 on T0.ItemCode = T2.ItemCode AND T2.PriceList = 2 LEFT JOIN want niet alle artikelen staan altijd in een prijslijst Voorbeeld van de WHERE in de JOIN opgenomen
GROUP BY / Aggregate Function Voorbeeld: SELECT T0.CardCode, T0.CardName, SUM(T1.DocTotal) as Bedrag FROM OCRD T0 INNER JOIN OQUT T1 on T0.CardCode = T1.CardCode GROUP BY T0.CardCode, T0.CardName OCRD CardCode CardName K0001 Klant 1 K0002 Klant 2 K0003 Klant 3 K0004 Klant 4 K0005 Klant 5 OQUT DocNum DocTotal CardCode 500001 250K0001 500002 358K0003 500003 145K0001 500004 250K0001 500005 200K0004 500006 150K0004 500007 350K0001 Resultaat CardCode CardName Bedrag K0001 Klant 1 945 K0003 Klant 3 358 K0004 Klant 4 350 Als je Aggregate functies gebruikt moet je groeperen Met aliassen kan je de kolomnaam bepalen
Aggregate Functions - voorbeelden Laagste - MIN Hoogste - MAX Som - SUM Gemiddelde - AVG Aantal - COUNT Standard Deviation - STDEV Variance - VAR SELECT T0.CardCode, SUM(T0.DocTotal) as 'Som', MIN(T0.DocTotal) as 'Laagste', MAX(T0.DocTotal) as 'Hoogste', AVG(T0.DocTotal) as 'Gemiddelde', COUNT(T0.DocNum) as 'Aantal' FROM OINV T0 GROUP BY T0.CardCode
OPDRACHT Maak een Query van alle klanten met: KlantCode, Klantnaam, Telefoonnummer klant, Hoogste factuurbedrag. Antwoord: SELECT T0.CardCode, T0.CardName, T0.Phone1, MAX(T1.DocTotal) as 'Bedrag' FROM OCRD T0 INNER JOIN OINV T1 on T0.CardCode = T1.CardCode GROUP BY T0.CardCode, T0.CardName, T0.Phone1
HAVING Voorbeeld: SELECT T0.CardCode, T0.CardName, SUM(T1.DocTotal) as Bedrag FROM OCRD T0 INNER JOIN OQUT T1 on T0.CardCode = T1.CardCode GROUP BY T0.CardCode, T0.CardName HAVING SUM(T1.DocTotal) > 500 OCRD CardCode CardName K0001 Klant 1 K0002 Klant 2 K0003 Klant 3 K0004 Klant 4 K0005 Klant 5 OQUT DocNum DocTotal CardCode 500001 250K0001 500002 358K0003 500003 145K0001 500004 250K0001 500005 200K0004 500006 150K0004 500007 350K0001 Resultaat CardCode CardName Bedrag K0001 Klant 1 945 Aggregate functions kan je niet in de WHERE gebruiken, die moeten in de HAVING
OPDRACHT Maak een Query van alle klanten met: KlantCode, Klantnaam, Telefoonnummer klant, Hoogste factuurbedrag. Met alleen klanten die een hogere factuur hebben dan 500 euro Antwoord: SELECT T0.CardCode, T0.CardName, T0.Phone1, MAX(T1.DocTotal) as 'Bedrag' FROM OCRD T0 INNER JOIN OINV T1 on T0.CardCode = T1.CardCode GROUP BY T0.CardCode, T0.CardName, T0.Phone1 HAVING MAX(T1.DocTotal) > 500
ORDER BY Voorbeeld: SELECT T0.CardCode, T0.CardName, T1.DocNum, T1.DocTotal FROM OCRD T0 INNER JOIN OQUT T1 on T0.CardCode = T1.CardCode ORDER BY T1.DocTotal DESC OCRD CardCode CardName K0001 Klant 1 K0002 Klant 2 K0003 Klant 3 K0004 Klant 4 K0005 Klant 5 OQUT DocNum DocTotal CardCode 500001 250K0001 500002 358K0003 500003 145K0001 500004 250K0001 500005 200K0004 500006 150K0004 500007 350K0001 Resultaat CardCode CardName DocNum DocTotal K0003 Klant 3 500002 358 K0001 Klant 1 500007 350 K0001 Klant 1 500001 250 K0001 Klant 1 500004 250 K0004 Klant 4 500005 200 K0004 Klant 4 500006 150 K0001 Klant 1 500003 145 Order By = Sorteren ASC = oplopend sorteren DESC = aflopend sorteren
Basis opbouw SQL Query SELECT FROM INNER JOIN ON = WHERE.. = AND.. =.. OR.. <> GROUP BY HAVING ORDER BY Samenvattend Volgorde opbouw staat vast Alleen de SELECT is verplicht Combinaties zijn mogelijk Meerdere JOINS Meerdere WHERE opties Etc.
Wat kan er nog meer? CASE CAST & CONVERT UNION ALL SUB-QUERY s Velden opmaken LOWER UPPER CONCAT REPLACE SUBSTRING LEN LEFT RIGHT Werken met datums Rekenen Vermenigvuldigen Delen Optellen Aftrekken Werken met VIEWS En nog veel meer!
CASE SELECT T0.ItemCode, T0.ItemName, CASE WHEN T0.QryGroup1 = 'Y' THEN 'Ja' WHEN T0.QryGroup1 = 'N' THEN 'Nee' END AS 'Eigenschap1' FROM OITM T0 SELECT T0.ItemCode, T0.ItemName, CASE WHEN T0.QryGroup1 = 'Y' THEN 'Ja' ELSE 'Nee' END AS 'Eigenschap1' FROM OITM T0 OITM ItemCode ItemName QryGroup1 A0001 Artikel 1 N A0002 Artikel 2 N A0003 Artikel 3 Y A0004 Artikel 4 N Resultaat ItemCode ItemName Eigenschap1 A0001 Artikel 1 Nee A0002 Artikel 2 Nee A0003 Artikel 3 Ja A0004 Artikel 4 Nee
OPDRACHT Maak een Query met alle artikelen: Artikelcode, Artikelomschrijving, Voorraad, Voorraadstatus Voorraadstatus Als voorraad kleiner dan 10 dan Weinig voorraad Als voorraad groter dan 10 en kleiner dan 100 dan Voldoende voorraad Als voorraad groter dan 100 dan Ruim voldoende voorraad Antwoord: SELECT T0.ItemCode, T0.ItemName, T0.OnHand, CASE WHEN T0.OnHand < 10 then 'Weinig voorraad' WHEN T0.OnHand > 10 and T0.OnHand < 100 then 'Voldoende voorraad' WHEN T0.OnHand > 100 then 'Ruim voldoende voorraad' END AS 'Voorraadstatus' FROM OITM T0 Letop! Hoe wordt voorraad 10 en voorraad 100 nu getoond?
Veld opmaak SELECT FirstName, LastName, LOWER(FirstName) as 'Lower', UPPER(LastName) as 'Upper', CONCAT(FirstName, ' ', LastName) as 'Concat', REPLACE(FirstName, 'r', '*' ) as 'Replace', SUBSTRING(FirstName, 1, 3 ) as 'Substring', LEN(FirstName) as 'Len', LEFT(FirstName, 2) as 'Left', RIGHT(FirstName, 2) as 'Right' FROM OCPR OCPR FirstName LastName Martin Treur Resultaat FirstName LastName Lower Upper Concat Replace Substring Len Left Right Martin Treur martin TREUR Martin Treur Ma*tin Mar 6Ma in
NULL NULL is niet hetzelfde als 0 of een lege string NULL is onbekend / niks SQL maakt verschil tussen een leeg veld en een veld waar een lege string of de waarde 0 in staat CardCode K1000 K1001 K1002 E_MailL NULL martin.treur@serac.nl ItemCode Price A0001 NULL A0002 0 A0003 3,75 SELECT T0.CardCode, T0.CardName, T0.E_Mail, ISNULL(E_Mail,'NB') as 'Email' FROM OCRD T0 WHERE ISNULL(T0.E_Mail, '') <> '' SELECT T0.ItemCode, T0.PriceList, T0.Price, ISNULL(T0.Price, 0) as 'Prijs' FROM ITM1 T0 WHERE ISNULL(T0.Price, 0) <> 0
Rekenen SELECT T0.DocNum, T0.DocTotal, T0.DocTotal * 1.2 AS 'Vermenigvuldigen', T0.DocTotal / 0.9 AS 'Delen', T0.DocTotal + 10 AS 'Optellen', T0.DocTotal - 7.5 AS 'Aftrekken' FROM ORDR T0 ORDR DocNum DocTotal 50000 100 50001 200 Resultaat DocNum DocTotal Vermenigvuldigen Delen Optellen Aftrekken 50000 100 120 90 110 92,50 50000 200 240 160 210 192,50
CAST & CONVERT CAST & CONVERT kunnen beide hetzelfde Omzetten van een veld naar een ander type veld Soms nodig om te kunnen samenvoegen of ermee te rekenen Vaak nodig om Datums anders te presenteren -- CAST Syntax: CAST ( expression AS data_type [ ( length ) ] ) -- CONVERT Syntax: CONVERT ( data_type [ ( length ) ], expression [, style ] ) Voorbeeld: SELECT ItmsGrpCod + '-' + ItmsGrpNam FROM OITB SELECT CAST(ItmsGrpCod as NVARCHAR(10)) + '-' + ItmsGrpNam, CONVERT(NVARCHAR(10), ItmsGrpCod) + '-' + ItmsGrpNam FROM OITB
Datums Voorbeeld datum in SAP Business One: SELECT T0.DocDate FROM ORDR T0 Datum + tijdstip veld Toont alleen de datum Huidige datum + tijdstip ophalen: SELECT GETDATE() Of SELECT CURRENT_TIMESTAMP
Datums converteren Een datum veld converteren naar ander formaat: select convert(varchar, getdate(), 1) --05/16/18 select convert(varchar, getdate(), 2) --18.05.16 select convert(varchar, getdate(), 3) --16/05/18 select convert(varchar, getdate(), 4) --16.05.18 select convert(varchar, getdate(), 5) --16-05-18 select convert(varchar, getdate(), 6) --16 May 18 select convert(varchar, getdate(), 7) --May 16, 18 select convert(varchar, getdate(), 10) --05-16-18 select convert(varchar, getdate(), 11) --16/05/30 select convert(varchar, getdate(), 12) --180516 select convert(varchar, getdate(), 13) --16 May 2018 12:03:01:800 select convert(varchar, getdate(), 14) --12:03:01:800 select convert(varchar, getdate(), 20) --2018-05-16 09:58:49 select convert(varchar, getdate(), 21) --2018-05-14 09:59:05.850
Datums converteren (2) 1 t/m 12 = YY 101 t/m 112 = YYYY select convert(varchar, getdate(), 101) --05/16/2018 select convert(varchar, getdate(), 102) --2018.05.16 select convert(varchar, getdate(), 103) --16/05/2018 select convert(varchar, getdate(), 104) --16.05.2018 select convert(varchar, getdate(), 105) --16-05-2018 select convert(varchar, getdate(), 106) --16 May 2018 select convert(varchar, getdate(), 107) --May 16, 2018 select convert(varchar, getdate(), 110) --05-16-2018 select convert(varchar, getdate(), 111) --2018/05/16 select convert(varchar, getdate(), 112) 20180516 select convert(varchar, getdate(), 113) --16 May 2018 12:51:08:697 select convert(varchar, getdate(), 114) --12:52:58:280 select convert(varchar, getdate(), 120) --2018-05-16 12:52:39 select convert(varchar, getdate(), 121) --2018-05-16 12:53:18.887
Datums gedeelte ophalen Een gedeelte van een datum ophalen: SELECT YEAR(T0.DocDate) AS 'Jaar' FROM ORDR T0 SELECT MONTH(T0.DocDate) AS 'Maand' FROM ORDR T0 SELECT DAY(T0.DocDate) AS 'Dag' FROM ORDR T0 SELECT DATEPART(YEAR, T0.DocDate) AS 'Jaar' FROM ORDR T0 SELECT DATEPART(QUARTER, T0.DocDate) AS 'Kwartaal' FROM ORDR T0 SELECT DATEPART(MONTH, T0.DocDate) AS 'Maand' FROM ORDR T0 SELECT DATEPART(WEEK, T0.DocDate) AS 'Week' FROM ORDR T0 SELECT DATEPART(ISO_WEEK, T0.DocDate) AS 'ISO Week' FROM ORDR T0 SELECT DATEPART(DAY, T0.DocDate) AS 'Dag van de maand' FROM ORDR T0 SELECT DATEPART(DAYOFYEAR, T0.DocDate) AS 'Dag van het jaar' FROM ORDR T0 SELECT DATEPART(WEEKDAY, T0.DocDate) AS 'Dag van de week' FROM ORDR T0 SELECT DATEPART(HOUR, GETDATE()) AS 'Uur van de dag' FROM ORDR T0 SELECT DATEPART(MINUTE, GETDATE()) AS 'Minuut van het uur' FROM ORDR T0
Rekenen met datums Het verschil tussen 2 datums ophalen: SELECT DATEDIFF (DAY, T0.DocDate, T0.DocDueDate) AS 'Dagen' FROM ORDR T0 SELECT DATEDIFF (WEEK, T0.DocDate, T0.DocDueDate) AS 'Weken' FROM ORDR T0 SELECT DATEDIFF (MONTH, T0.DocDate, T0.DocDueDate) AS 'Maanden' FROM ORDR T0 SELECT DATEDIFF (QUARTER, T0.DocDate, T0.DocDueDate) AS 'Kwartalen' FROM ORDR T0 SELECT DATEDIFF (YEAR, T0.DocDate, T0.DocDueDate) AS 'Jaren' FROM ORDR T0
UNION ALL SELECT T0.CardCode, T0.DocNum, T0.DocTotal FROM OINV T0 UNION ALL SELECT T0.CardCode, T0.DocNum, T0.DocTotal FROM ORIN T0 OINV CardCode DocNum DocTotal K0001 500001 250 K0003 500002 358 K0001 500003 145 K0001 500004 250 ORIN CardCode DocNum DocTotal K0001 600001 200 K0003 600002 300 Resultaat CardCode DocNum DocTotal K0001 500001 250 K0003 500002 358 K0001 500003 145 K0001 500004 250 K0001 600001 200 K0003 600002 300 Combineert de resultaten van query s in 1 overzicht Aantal velden en type velden moeten gelijk zijn in de query s
SUBQUERY s In de WHERE SELECT T0.CardCode, T0.CardName, T0.Phone1 FROM OCRD T0 WHERE T0.CardCode in ( SELECT T20.CardCode FROM ORDR T20 WHERE T20.DocDueDate = CONVERT (date, GETDATE()) ) OCRD CardCode CardName Phone1 K0001 Klant 1 0348-123456 K0002 Klant 2 0348-123457 K0003 Klant 3 0348-123458 ORDR DocNum CardCode DocDueDate 40000K0001 5/16/2018 40001K0001 5/19/2018 40002K0002 5/19/2018 40003K0002 5/21/2018 40004K0001 5/21/2018 40005K0003 5/16/2018 Resultaat CardCode CardName Phone1 K0001 Klant 1 0348-123456 K0003 Klant 3 0348-123458
OPDRACHT Maak een Query met alle Klanten: Klantcode, Klantnaam, Telefoonnummer Toon alleen klanten die de afgelopen 10 dagen een order hebben geplaatst Gebruik hierbij een SUBQUERY Antwoord: SELECT T0.CardCode, T0.CardName, T0.Phone1 FROM OCRD T0 WHERE T0.CardCode in ( SELECT T20.CardCode FROM ORDR T20 WHERE T20.DocDate > GETDATE() - 10 )
SUBQUERY s In de SELECT SELECT T0.CardCode, T0.CardName, T0.Phone1, (SELECT COUNT(T10.DocTotal) FROM ORDR T10 WHERE T0.CardCode = T10.CardCode) as AantalOrders', (SELECT MAX(T20.DocDate) FROM ORDR T20 WHERE T0.CardCode = T20.CardCode) as 'LaatsteOrder', (SELECT SUM(T20.DocTotal) FROM ORDR T20 WHERE T0.CardCode = T20.CardCode) as Totaal' FROM OCRD T0 OCRD CardCode CardName Phone1 K0001 Klant 1 0348-123456 K0002 Klant 2 0348-123457 K0003 Klant 3 0348-123458 ORDR DocNum CardCode DocDate DocTotal 40000K0001 5/16/2018 250 40001K0001 5/19/2018 500 40002K0002 5/19/2018 250 40003K0002 5/21/2018 100 40004K0001 5/21/2018 400 40005K0003 5/25/2018 500 Resultaat CardCode CardName Phone1 AantalOrders LaatsteOrder Totaal K0001 Klant 1 0348-123456 3 5/21/2018 1150 K0002 Klant 2 0348-123457 2 5/21/2018 350 K0003 Klant 3 0348-123458 1 5/25/2018 500
OPDRACHT Maak een Query met: Klantcode, Klantnaam, Omzet in 2018 Mail je antwoord naar: martin.treur@serac.nl
Antwoord voorbeeld 1 SELECT CardCode, CardName, SUM(RegelOmzet) as 'Omzet 2018' FROM ( SELECT t0.cardcode, t0.cardname, t2.linetotal * ((100 - ISNULL(t1.DiscPrcnt, 0)) / 100) AS 'RegelOmzet' FROM OCRD t0 INNER JOIN OINV t1 ON t0.cardcode = t1.cardcode INNER JOIN INV1 t2 ON t1.docentry = t2.docentry LEFT JOIN OACT T11 on T2.AcctCode = T11.AcctCode WHERE t1.canceled = 'N' AND T11.ActType = 'I' AND YEAR(T1.DocDate) = 2018 UNION ALL SELECT t0.cardcode, t0.cardname, t2.linetotal * ((100 - ISNULL(t1.DiscPrcnt, 0)) / 100) * -1 AS 'RegelOmzet' FROM OCRD t0 INNER JOIN ORIN t1 ON t0.cardcode = t1.cardcode INNER JOIN RIN1 t2 ON t1.docentry = t2.docentry LEFT JOIN OACT T11 on T2.AcctCode = T11.AcctCode WHERE t1.canceled = 'N' AND T11.ActType = 'I' AND t2.basetype <> '203' AND YEAR(T1.DocDate) = 2018 ) as T1 GROUP BY CardCode, CardName
Antwoord voorbeeld 2 SELECT T0.CardCode, T0.CardName, ( SELECT SUM(ISNULL(T10.DocTotal,0)) - SUM(ISNULL(T10.VatSum,0)) - SUM(ISNULL(T10.DiscSum,0)) FROM OINV T10 WHERE T0.CardCode = T10.CardCode AND T10.CANCELED = 'N' AND YEAR(T10.DocDate) = 2018 ) - ISNULL( (SELECT SUM(ISNULL(T20.DocTotal,0)) - SUM(ISNULL(T20.VatSum,0)) - SUM(ISNULL(T20.DiscSum,0)) FROM ORIN T20 WHERE T0.CardCode = T20.CardCode AND T20.CANCELED = 'N' AND YEAR(T20.DocDate) = 2018 ),0) FROM OCRD T0
OPDRACHT Maak een Query met: Klantcode, Klantnaam, Omzet in 2016, Omzet in 2017, Omzet in 2018, Mail je antwoord naar: martin.treur@serac.nl
VIEWS Je kunt een query ook opslaan als een view De query resultaat (view) gedraagt zich dan als een tabel Werkwijze Eenmalig een basis query maken (view) Vervolgens andere query s daarop uitvoeren Voordelen Uniformiteit Tijdsbesparing Voorkomen van fouten Etc.
Voorbeeld gebruik VIEW SELECT * FROM SE_OMZET SELECT T0.CardCode, T0.CardName, SUM(T1.RegelOmzet) as 'Omzet 2018' FROM OCRD T0 LEFT JOIN SE_OMZET T1 on T0.CardCode = T1.CardCode and YEAR(T1.DocDate) = 2018 GROUP BY T0.CardCode, T0.CardName SELECT T0.CardCode, T0.CardName, (SELECT SUM(T10.RegelOmzet) FROM SE_OMZET T10 WHERE T0.CardCode = T10.CardCode AND YEAR(T10.DocDate) = 2014) as 'Omzet 2014', (SELECT SUM(T11.RegelOmzet) FROM SE_OMZET T11 WHERE T0.CardCode = T11.CardCode AND YEAR(T11.DocDate) = 2015) as 'Omzet 2015', (SELECT SUM(T12.RegelOmzet) FROM SE_OMZET T12 WHERE T0.CardCode = T12.CardCode AND YEAR(T12.DocDate) = 2016) as 'Omzet 2016', (SELECT SUM(T13.RegelOmzet) FROM SE_OMZET T13 WHERE T0.CardCode = T13.CardCode AND YEAR(T13.DocDate) = 2017) as 'Omzet 2017', (SELECT SUM(T14.RegelOmzet) FROM SE_OMZET T14 WHERE T0.CardCode = T14.CardCode AND YEAR(T14.DocDate) = 2018) as 'Omzet 2018' FROM OCRD T0
Performance tips Haal alleen velden op die je echt nodig hebt Geen onnodige tabellen gebruiken Gebruik INNER JOIN i.p.v. LEFT JOIN als het kan Gebruik HAVING alleen voor filteren van Aggregate velden Gebruik WITH (NOLOCK)
WITH (NOLOCK) Deadlocks kunnen ontstaan als tegelijk data wordt opgehaald en wordt weggeschreven in een tabel. Voorkom deadlocks door WITH (NOLOCK) toe te voegen aan je query s. Voorbeeld: SELECT T0.DocNum, T0.CardName, T1.ItemCode, T2.ItemName, T1.Quantity FROM ORDR T0 INNER JOIN RDR1 T1 WITH (NOLOCK) ON T0.DocEntry = T1.DocEntry INNER JOIN OITM T2 WITH (NOLOCK) ON T1.ItemCode = T2.ItemCode
Algemene Query tips Schrijf je Query overzichtelijk Voeg bij lange / complexe Query s commentaar toe Controleer je Query resultaat meerdere keren op juistheid Indien je vaker dezelfde tabellen nodig hebt, overweeg een VIEW In plaats van de WHERE gebruik de filter mogelijkheid in SAP Business One Werkt je query ook nog als er een nieuw magazijn / klant / artikelgroep wordt aangemaakt? Of een nieuw jaar begint? -- Voorbeeld commentaar SELECT T0.CardCode, T0.CardName FROM OCRD T0
MSSQL vs HANA MSSQL: SELECT T0.ItemCode FROM OITM T0 HANA: SELECT T0."ItemCode" FROM OITM T0 ; MSSQL HANA T-SQL ANSI Niet hoofdletter gevoelig Wel hoofdletter gevoelig CAST & CONVERT CAST Geen Queryblok afsluiting Afsluiting met ; ISNULL IFNULL Getdate() & current_timestamp current_timestamp
Query s visualiseren
Zelfstudie Websites https://www.w3schools.com/sql/ https://stackoverflow.com/questions/tagged/sql Boeken https://www.bol.com/nl/p/mastering-sql-queries-for-sap-business-one/9200000005212111/ https://www.bol.com/nl/f/sql-in-24-hours/9200000045507758/ https://www.bol.com/nl/p/sql-de-basis/1001004002723006/
martin.treur@serac.nl Vragen?
Serac Serac Rijnzathe 36/Postbus 83 3454 PV / 3454 ZH de Meern Telefoon: 030 65 83 333 Email: info@serac.nl