Serac - SAP Business One - Workshop SQL Workshop...Datums. datetime Datum + tijdstip date Datum. •...
Transcript of Serac - SAP Business One - Workshop SQL Workshop...Datums. datetime Datum + tijdstip date Datum. •...
Workshop SQL
Woensdag 16 mei 2018
Introductie
Mike WinkelMartin 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 / Stringschar(n) String veld met vaste lengte Max 8000 karaktersnvarchar(n) Unicode String veld met variabele lengte Max 4000 karaktersntext Unicode String veld met variabele lengte Max 2GB text data
Numeriekint Gehele getallen tussen -2147483648 en 2147483647smallint Gehele getallen tussen -32768 en 32767numeric(19, 6) Getal met maximaal 6 cijfers na de komma, totaal 19 cijfers
Datumsdatetime Datum + tijdstipdate 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, informatiewegschrijven, 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, CardNameFROM OCRDWHERE 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 resultatenvoldoen
Tabellen combineren – INNER JOIN
Voorbeeld:SELECT T0.CardCode, T0.CardName, T1.DocNum, T1.DocTotalFROM OCRD T0INNER 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
Antwoord:SELECTT0.ItemCode,T0.ItemName,T1.ItmsGrpCod,T1.ItmsGrpNamFROM OITM T0INNER JOIN OITB T1 on T0.ItmsGrpCod = T1.ItmsGrpCod
Maak een Query van alle artikelen met:Artikelcode, Artikelomschrijving, Artikelgroep code, Artikelgroep naam
Tabellen combineren – LEFT JOIN
Voorbeeld:SELECT T0.CardCode, T0.CardName, T1.DocNum, T1.DocTotalFROM OCRD T0LEFT 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
• LEFT JOIN haalt alle resultaten op uit de “linker” tabel
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
OPDRACHT
Antwoord:SELECTT0.ItemCode,T0.ItemName,T1.CardCode,T1.CardNameFROM OITM T0LEFT JOIN OCRD T1 on T0.CardCode = T1.CardCode
• LEFT JOIN want niet alle artikelen hebben verplicht een hoofdleverancier
Maak een Query van alle artikelen met:Artikelcode, Artikelomschrijving, Hoofdleverancier code, Hoofdleverancier naam
Tabellen combineren – CROSS JOIN
Voorbeeld:SELECT t0.AcctCode, t0.AcctName, T1.OcrCode, T1.OcrNameFROM OACT T0CROSS JOIN OOCR T1ORDER BY t0.AcctCode
• CROSS JOIN haalt alle combinaties op uit de “linker” tabel en “rechter” tabel
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
Tabellen combineren – Overzicht JOINS
WHERE
Voorbeeld:SELECT T0.CardCode, T0.CardName, T1.DocNum, T1.DocTotalFROM OCRD T0INNER JOIN OQUT T1 on T0.CardCode = T1.CardCodeWHERE 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
• In de WHERE kan je voorwaarden zetten (filteren)
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
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 NULLIS NOT NULL - IS NOT NULLKomt voor in - IN ('_','_','_')
Voorwaarden ook te combineren met:En - ANDOf - OR
OPDRACHT
Antwoord:SELECTT0.CardCode, T0.CardName, T1.Name, T1.Tel1, T1.E_MailLFROM OCRD T0LEFT JOIN OCPR T1 on T0.CardCode = T1.CardCodeWHERET0.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 ()
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
WHERE opnemen in de JOIN
Voorbeeld:SELECT T0.CardCode, T0.CardName, T1.DocNum, T1.DocTotalFROM OCRD T0INNER 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
• Je kunt de WHERE ook direct opnemen in de JOIN
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
OPDRACHT
Antwoord:SELECTT0.ItemCode,T0.ItemName,T1.Price as 'Inkoopprijs',T2.Price as 'Verkoopprijs'FROM OITM T0LEFT JOIN ITM1 T1 on T0.ItemCode = T1.ItemCode AND T1.PriceList = 1LEFT 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
Maak een Query van alle artikelen met:Artikelcode, Artikelomschrijving, Inkoopprijs, Bruto verkoopprijs
GROUP BY / Aggregate Function
Voorbeeld:SELECT T0.CardCode, T0.CardName, SUM(T1.DocTotal) as ‘Bedrag’FROM OCRD T0INNER JOIN OQUT T1 on T0.CardCode = T1.CardCodeGROUP 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
• Als je Aggregate functies gebruikt moet je groeperen• Met aliassen kan je de kolomnaam bepalen
Resultaat
CardCode CardName Bedrag
K0001 Klant 1 945
K0003 Klant 3 358
K0004 Klant 4 350
Aggregate Functions - voorbeelden
Laagste - MINHoogste - MAXSom - SUMGemiddelde - AVGAantal - COUNT
Standard Deviation - STDEVVariance - VAR
SELECTT0.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 T0GROUP BY T0.CardCode
OPDRACHT
Antwoord:SELECTT0.CardCode,T0.CardName,T0.Phone1,MAX(T1.DocTotal) as 'Bedrag'FROM OCRD T0INNER JOIN OINV T1 on T0.CardCode = T1.CardCodeGROUP BY T0.CardCode, T0.CardName, T0.Phone1
Maak een Query van alle klanten met:• KlantCode, Klantnaam, Telefoonnummer klant, Hoogste factuurbedrag.
HAVING
Voorbeeld:SELECT T0.CardCode, T0.CardName, SUM(T1.DocTotal) as ‘Bedrag’FROM OCRD T0INNER JOIN OQUT T1 on T0.CardCode = T1.CardCodeGROUP BY T0.CardCode, T0.CardNameHAVING 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
• Aggregate functions kan je niet in de WHERE gebruiken, die moeten in de HAVING
Resultaat
CardCode CardName Bedrag
K0001 Klant 1 945
OPDRACHT
Antwoord:SELECTT0.CardCode,T0.CardName,T0.Phone1,MAX(T1.DocTotal) as 'Bedrag'FROM OCRD T0INNER JOIN OINV T1 on T0.CardCode = T1.CardCodeGROUP BY T0.CardCode, T0.CardName, T0.Phone1HAVING MAX(T1.DocTotal) > 500
Maak een Query van alle klanten met:• KlantCode, Klantnaam, Telefoonnummer klant, Hoogste factuurbedrag.• Met alleen klanten die een hogere factuur hebben dan 500 euro
ORDER BY
Voorbeeld:SELECT T0.CardCode, T0.CardName, T1.DocNum, T1.DocTotalFROM OCRD T0INNER JOIN OQUT T1 on T0.CardCode = T1.CardCodeORDER 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
• Order By = Sorteren• ASC = oplopend sorteren• DESC = aflopend sorteren
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
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
En nog veel meer!
• Werken met datums• Rekenen
• Vermenigvuldigen• Delen• Optellen• Aftrekken
• Werken met VIEWS
CASE
SELECT T0.ItemCode, T0.ItemName,
CASEWHEN T0.QryGroup1 = 'Y' THEN 'Ja'WHEN T0.QryGroup1 = 'N' THEN 'Nee'
END AS 'Eigenschap1'FROM OITM T0
SELECT T0.ItemCode, T0.ItemName,
CASEWHEN 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
Antwoord:SELECTT0.ItemCode,T0.ItemName,T0.OnHand,CASEWHEN 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?
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”
Veld opmaak
SELECTFirstName,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
Resultaat
FirstName LastName Lower Upper Concat Replace Substring Len Left Right
Martin Treur martin TREUR Martin Treur Ma*tin Mar 6Ma in
OCPR
FirstName LastName
Martin Treur
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
SELECTT0.ItemCode,T0.PriceList,T0.Price,ISNULL(T0.Price, 0) as 'Prijs'FROM ITM1 T0WHEREISNULL(T0.Price, 0) <> 0
CardCode E_MailL
K1000 NULL
K1001
K1002 [email protected]
ItemCode Price
A0001 NULL
A0002 0
A0003 3,75
SELECTT0.CardCode,T0.CardName,T0.E_Mail,ISNULL(E_Mail,'NB') as 'Email'FROM OCRD T0WHEREISNULL(T0.E_Mail, '') <> ''
Rekenen
SELECTT0.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
SELECTCAST(ItmsGrpCod as NVARCHAR(10)) + '-' + ItmsGrpNam,CONVERT(NVARCHAR(10), ItmsGrpCod) + '-' + ItmsGrpNamFROM 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()OfSELECT CURRENT_TIMESTAMP
Datums converteren
Een datum veld converteren naar ander formaat:
select convert(varchar, getdate(), 1) --05/16/18select convert(varchar, getdate(), 2) --18.05.16select convert(varchar, getdate(), 3) --16/05/18select convert(varchar, getdate(), 4) --16.05.18select convert(varchar, getdate(), 5) --16-05-18select convert(varchar, getdate(), 6) --16 May 18select convert(varchar, getdate(), 7) --May 16, 18select convert(varchar, getdate(), 10) --05-16-18select convert(varchar, getdate(), 11) --16/05/30select convert(varchar, getdate(), 12) --180516select convert(varchar, getdate(), 13) --16 May 2018 12:03:01:800select convert(varchar, getdate(), 14) --12:03:01:800select convert(varchar, getdate(), 20) --2018-05-16 09:58:49select convert(varchar, getdate(), 21) --2018-05-14 09:59:05.850
Datums converteren (2)
1 t/m 12 = YY101 t/m 112 = YYYY
select convert(varchar, getdate(), 101) --05/16/2018select convert(varchar, getdate(), 102) --2018.05.16select convert(varchar, getdate(), 103) --16/05/2018select convert(varchar, getdate(), 104) --16.05.2018select convert(varchar, getdate(), 105) --16-05-2018select convert(varchar, getdate(), 106) --16 May 2018select convert(varchar, getdate(), 107) --May 16, 2018select convert(varchar, getdate(), 110) --05-16-2018select convert(varchar, getdate(), 111) --2018/05/16 select convert(varchar, getdate(), 112) –20180516
select convert(varchar, getdate(), 113) --16 May 2018 12:51:08:697select convert(varchar, getdate(), 114) --12:52:58:280select convert(varchar, getdate(), 120) --2018-05-16 12:52:39select 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 T0SELECT MONTH(T0.DocDate) AS 'Maand' FROM ORDR T0SELECT DAY(T0.DocDate) AS 'Dag' FROM ORDR T0
SELECT DATEPART(YEAR, T0.DocDate) AS 'Jaar' FROM ORDR T0SELECT DATEPART(QUARTER, T0.DocDate) AS 'Kwartaal' FROM ORDR T0SELECT DATEPART(MONTH, T0.DocDate) AS 'Maand' FROM ORDR T0SELECT DATEPART(WEEK, T0.DocDate) AS 'Week' FROM ORDR T0SELECT DATEPART(ISO_WEEK, T0.DocDate) AS 'ISO Week' FROM ORDR T0SELECT DATEPART(DAY, T0.DocDate) AS 'Dag van de maand' FROM ORDR T0SELECT DATEPART(DAYOFYEAR, T0.DocDate) AS 'Dag van het jaar' FROM ORDR T0SELECT DATEPART(WEEKDAY, T0.DocDate) AS 'Dag van de week' FROM ORDR T0SELECT DATEPART(HOUR, GETDATE()) AS 'Uur van de dag' FROM ORDR T0SELECT 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 T0SELECT DATEDIFF (WEEK, T0.DocDate, T0.DocDueDate) AS 'Weken' FROM ORDR T0SELECT DATEDIFF (MONTH, T0.DocDate, T0.DocDueDate) AS 'Maanden' FROM ORDR T0SELECT DATEDIFF (QUARTER, T0.DocDate, T0.DocDueDate) AS 'Kwartalen' FROM ORDR T0SELECT DATEDIFF (YEAR, T0.DocDate, T0.DocDueDate) AS 'Jaren' FROM ORDR T0
UNION ALL
SELECT T0.CardCode, T0.DocNum, T0.DocTotalFROM OINV T0
UNION ALL
SELECT T0.CardCode, T0.DocNum, T0.DocTotalFROM 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 T0WHERET0.CardCode in (SELECT T20.CardCode FROM ORDR T20WHERE 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
Antwoord:SELECT T0.CardCode, T0.CardName, T0.Phone1 FROM OCRD T0WHERET0.CardCode in(SELECT T20.CardCode FROM ORDR T20WHERE T20.DocDate > GETDATE() - 10)
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
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
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
OCRD
CardCode CardName Phone1
K0001 Klant 1 0348-123456
K0002 Klant 2 0348-123457
K0003 Klant 3 0348-123458
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:
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.AcctCodeWHERE 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.AcctCodeWHERE t1.CANCELED = 'N' AND T11.ActType = 'I' AND t2.basetype <> '203'AND YEAR(T1.DocDate) = 2018
) as T1GROUP BY CardCode, CardName
Antwoord voorbeeld 2
SELECTT0.CardCode,T0.CardName,(SELECTSUM(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((SELECTSUM(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:
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 T0LEFT JOIN SE_OMZET T1 on T0.CardCode = T1.CardCode and YEAR(T1.DocDate) = 2018GROUP BY T0.CardCode, T0.CardName
SELECTT0.CardCode,T0.CardName,(SELECT SUM(T10.RegelOmzet) FROM SE_OMZET T10 WHERE T0.CardCode = T10.CardCode ANDYEAR(T10.DocDate) = 2014) as 'Omzet 2014',(SELECT SUM(T11.RegelOmzet) FROM SE_OMZET T11 WHERE T0.CardCode = T11.CardCode ANDYEAR(T11.DocDate) = 2015) as 'Omzet 2015',(SELECT SUM(T12.RegelOmzet) FROM SE_OMZET T12 WHERE T0.CardCode = T12.CardCode ANDYEAR(T12.DocDate) = 2016) as 'Omzet 2016',(SELECT SUM(T13.RegelOmzet) FROM SE_OMZET T13 WHERE T0.CardCode = T13.CardCode ANDYEAR(T13.DocDate) = 2017) as 'Omzet 2017',(SELECT SUM(T14.RegelOmzet) FROM SE_OMZET T14 WHERE T0.CardCode = T14.CardCode ANDYEAR(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:
SELECTT0.DocNum,T0.CardName,T1.ItemCode,T2.ItemName,T1.QuantityFROM ORDR T0INNER 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 commentaarSELECTT0.CardCode, T0.CardName FROM OCRD T0
MSSQL vs HANA
MSSQL HANAT-SQL ANSINiet hoofdletter gevoelig Wel hoofdletter gevoeligCAST & CONVERT CASTGeen Queryblok afsluiting Afsluiting met ;ISNULL IFNULLGetdate() & current_timestamp current_timestamp
MSSQL: SELECT T0.ItemCode FROM OITM T0HANA: SELECT T0."ItemCode" FROM OITM T0 ;
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/
Serac
Rijnzathe 36/Postbus 83
3454 PV / 3454 ZH de Meern
Telefoon: 030 65 83 333
Email: [email protected]
Serac