Wednesday 18 October 2023

Making API POST Requests with JSON and Authentication Token using C# Class Library as reference in D365FO

 In today's interconnected world, integrating with external APIs is a common requirement for many software projects. Whether you're building a web application, mobile app, or any other software that needs to communicate with external services, understanding how to make API POST requests with JSON data and authentication tokens in a C# class library can be incredibly valuable. In this blog post, we'll walk you through the process of creating a C# class library that can be used as a reference for making such requests.

Step 1: Create a C# Class Library Project

To create a C# class library project in Visual Studio that compiles into a .dll (Dynamic-Link Library) file, you can follow these steps:

1. Open Visual Studio:

If you don't have Visual Studio installed, you can download the Community edition for free from the official Microsoft website.

2. Create a New Project:

Go to "File" > "New" > "Project..."

In the "Create a new project" window, search for "Class Library" or "Class Library (.NET Core)" depending on the version of .NET you want to target.

Select the appropriate project template and click "Next."

Add the below C# code:

-----------------------------------------------------------------------------------------------------------------------

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

using System.Net.Http;

using System.Net.Http.Headers;


namespace CSharpAPIClassLibrary

{

    public class AXApiService

    {

        private readonly HttpClient httpClient;

        public AXApiService(string baseUri)

        {

            httpClient = new HttpClient { BaseAddress = new Uri(baseUri) };

        }

        public async Task<string> PostDataAsync(string endpoint, string jsonContent, string authToken)

        {

            try

            {

                httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", authToken);

                httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

                var content = new StringContent(jsonContent, Encoding.UTF8, "application/json");

                HttpResponseMessage response = await httpClient.PostAsync(endpoint, content);

                if (response.IsSuccessStatusCode)

                {

                    return await response.Content.ReadAsStringAsync();

                }

                throw new Exception($"API request failed with status code {response.StatusCode}");

            }

            catch (Exception ex)

            {

                throw new Exception($"API request failed: {ex.Message}");

            }

        }

    }

}

-------------------------------------------------------------------------------------------------------------------------

3. Build the Project:

        a)Build your class library project by clicking "Build" > "Build Solution" or using the keyboard shortcut (usually F6).
        b)This action will compile your code into a .dll file.

4. Locate the .dll File:

        a)The compiled .dll file can be found in the "bin" folder of your project. By default, it's in a subfolder named after your target framework (e.g., "bin\Debug\netstandard2.0" for a .NET Standard 2.0 project).
Your C# class library is now compiled into a .dll file and is ready to be used in other projects or applications. You can reference this .dll in other C# projects, such as console applications, Windows Forms applications, ASP.NET applications, or any other .NET application type.

Note: 

This ApiClient class allows you to set the base URL, make POST requests with JSON payloads, and include an authentication token in the headers.

Step 2: Use the API Client in Your Application

    a)To use this library in an Application Object Tree (AOT) project, add a reference to your class library by right-clicking on the AOT project, selecting "Add Reference," and then browsing for your class library's DLL file in the bin/Debug (or bin/Release) folder of your class library project.

    b)In your AOT project, you can now use the ApiService class to make API calls with the desired content type and authorization token.

Here's an example of how you can use this class in your AOT project:

using CSharpAPIClassLibrary;
internal final class CallCshrpLibAPIPostEmp
{
    /// <summary>
    /// Class entry point. The system will call this method when a designated menu 
    /// is selected or when execution starts and this class is set as the startup class.
    /// </summary>
    /// <param name = "_args">The specified arguments.</param>
    public static void main(Args _args)
    {
        var axApiService = new AXApiService("https://api.example.com"); // Base URL
        str endpoint = "/api/resource"; //endPoint POST URL       
        str jsonContent = "{ \"key\": \"value\" }";
        str authToken = = "your-auth-token";

        try
        {
            str response = axApiService.PostDataAsync(endpoint, jsonContent, authToken).Result;
            info("API response: " + response);
        }
        catch (Exception::Error)
        {
            // Handle exceptions that may occur during the request
            error("An error occurred during the HTTP request.");
        }
    }

}


You've now created a C# class library that can be used as a reference for making API POST requests with JSON data and authentication tokens. This library can be reused in various C# applications, making it easier to integrate with external APIs securely and efficiently.

Remember to handle errors and edge cases according to your application's specific requirements and consult the API's documentation for any additional details. Happy coding! ---Mallik

Tuesday 17 October 2023

Calling APIs from D365 Using Content Type Text "application/x-www-form-urlencoded" POST request

 

In the world of enterprise resource planning (ERP), Microsoft Dynamics 365 (D365) stands out as a powerful and versatile solution. To unlock the full potential of D365, you often need to integrate it with other systems or automate certain processes. One common way to achieve this is by calling D365 APIs. In this blog post, we'll walk you through the process of calling D365 APIs using the "application/x-www-form-urlencoded" content type.

Understanding the "application/x-www-form-urlencoded" Content Type

Before we dive into calling D365 APIs, let's first understand what the "application/x-www-form-urlencoded" content type is. This content type is commonly used for sending data to web servers, especially when dealing with HTML forms. It represents key-value pairs in the URL-encoded format, where data is sent as a series of name-value pairs separated by the '&' character.

Prerequisites

To start calling D365 APIs, you'll need the following prerequisites:

1. Microsoft Dynamics 365 Account: You should have access to a D365 instance and the required permissions to call APIs.

2. API Endpoint: You should know the API endpoint you want to call. Consult D365's API documentation to find the specific endpoint URL.

3. API Key or Authentication Token: Depending on your D365 instance's security settings, you might need an API key or an authentication token.

Calling D365 APIs with "application/x-www-form-urlencoded" Content Type

Now, let's walk through the steps to call a D365 API using the "application/x-www-form-urlencoded" content type:

Step 1: Assemble Your Data

Prepare the data you want to send in the request in the "application/x-www-form-urlencoded" format. This means you need to create a string that contains key-value pairs separated by '&' and encode them properly.

Step 2: Set Up Your HTTP Request below is the sample code 

using Newtonsoft.Json.Linq;

using Newtonsoft.Json.JsonSerializer;

using System.Text.Json;

using System.IO.FileAccess;

using System.IO.Directory;

using System.IO;

using Newtonsoft.Json.Linq.JObject;

using System.Net.Http.HttpClient;

using System.Net.Http.HttpRequestMessage ;

using System.Net.Http.HttpResponseMessage;

internal final class AuthenticationRunnableClass

{

    /// <summary>

    /// Class entry point. The system will call this method when a designated menu 

    /// is selected or when execution starts and this class is set as the startup class.

    /// </summary>

    /// <param name = "_args">The specified arguments.</param>

    public static void main(Args _args)

    {

        System.Net.Http.HttpClient clientlocal;

        System.Net.Http.HttpRequestMessage requestlocal;

        System.Net.Http.HttpResponseMessage responselocal;

        System.Text.Encoding encoding;

        try

        {

            // Create an instance of the HttpClient

            clientlocal = new System.Net.Http.HttpClient();

            // Define the request URL

            str requestUrl = 'https://your-d365-api-endpoint.com';

    // Create the content in application/x-www-form-urlencoded format

            str formData = 'client_id=xx-xxxx&client_secret=xxxxx&grant_type=client_credentials&scope=alf.scope.integration.api&acr_values=tenant:xxxx'; // Replace with your form data //This is the text which is used to send with URL

            encoding = System.Text.Encoding::UTF8;

            // Create the content as StringContent

            System.Net.Http.StringContent content = new System.Net.Http.StringContent(formData, encoding, 'application/x-www-form-urlencoded');

            // Send the POST request with the form data

            responselocal = clientlocal.postAsync(requestUrl, content).Result;

            // Handle the response as needed

            int statusCode = any2Int(responselocal.get_StatusCode());

            str responseContent = responselocal.get_Content().readAsStringAsync().Result;

            // Handle the response data and potential errors

            if (statusCode == 200)

            {

                // Request was successful; process the response content

                info(responseContent);

            }

            else

            {

                // Handle the response based on the status code (e.g., log an error)

                error("HTTP request failed with status code: " + int2str(statusCode));

            }

        }

        catch (Exception::Error)

        {

            // Handle exceptions that may occur during the request

            error("An error occurred during the HTTP request.");

        }

    }

}

Step 3: Handle the Response

Once you send the request, you can handle the response from the D365 API. Be sure to check the status code and parse the response data accordingly. The code below show how to handle the response 

// Handle the response data and potential errors

            if (statusCode == 200)

            {

                // Request was successful; process the response content

                info(responseContent);

            }

            else

            {

                // Handle the response based on the status code (e.g., log an error)

                error("HTTP request failed with status code: " + int2str(statusCode));

            }


Conclusion

Calling D365 APIs using the "application/x-www-form-urlencoded" content type is a common way to integrate D365 with other systems or automate processes. Understanding the format and following the steps outlined in this blog post can help you make successful API requests and leverage the full power of Microsoft Dynamics 365. Make sure to refer to D365's API documentation for the specific endpoints and data you need to interact with in your integration projects.






Friday 8 September 2023

Managing Missing Attachments in DocuView for Dynamics 365 Finance and Operations

 

Introduction

In today's digital age, data management and document handling are crucial aspects of any business operation. In Dynamics 365 Finance and Operations (D365 FO), the DocuView feature offers a seamless way to attach and manage documents related to various records within the system. However, occasionally, you may encounter the issue of missing attachments, especially when working with transactions like posted general journals. In this blog post, we will explore the steps to add attachments to posted general journals and address the problem of missing attachments in DocuView.

Understanding DocuView in D365 FO

DocuView is a powerful feature in D365 FO that allows users to attach documents and files directly to records such as sales orders, purchase orders, general journals, and more. This feature enhances document management, streamlines business processes, and ensures that important information is readily accessible.

The Challenge: Missing Attachments on Posted General Journals

One common issue that users may encounter is missing attachments on posted general journals. This can be problematic when trying to track and access crucial documents related to financial transactions. Fortunately, this issue can be resolved by following a few straightforward steps.

Adding Attachments to Posted General Journals

To ensure that attachments are not missing on posted general journals, you can follow these steps:

Step 1: Access the Posted General Journal

  1. Navigate to the 'General ledger' module in D365 FO.
  2. Select 'Journal entries' under the 'Journal setup' section.
  3. Locate and open the posted general journal that requires an attachment.

Step 2: Attach the Document

  1. Once the journal is open, click on the 'Lines' button to view the journal lines.
  2. Select the specific journal line to which you want to attach a document.
  3. In the 'Attachments' tab, click on 'Attach file.'
  4. Choose the file you want to attach from your computer or network drive.
  5. Provide a brief description for the attachment to make it easily identifiable.
  6. Click 'OK' to save the attachment.

Step 3: Verify the Attachment

  1. After attaching the document, go back to the 'Attachments' tab to ensure that it appears under the journal line.
  2. You can view, open, or remove the attachment as needed.

Preventing Missing Attachments

To prevent missing attachments on posted general journals or other records in D365 FO, consider the following best practices:

Adding the ledger journal table as active document table

To be able to do that you have to enter the 'Ledger journal table' as an active document table in the Organization Administration module->Document Management->Active document tables-- and selecting the field 'Always enabled’ for the tables like ledger journal.

A screenshot of a computer

Description automatically generated

 

Conclusion

DocuView in Dynamics 365 Finance and Operations offers an excellent solution for document management and attachment. By following the steps outlined in this blog post, you can easily add attachments to posted general journals and minimize the risk of missing attachments. Furthermore, adopting best practices for document management will help you maintain a well-organized and efficient system, ensuring that your critical documents are always at your fingertips.

 

Tuesday 8 August 2023

A Step-by-Step Guide to Installing Dynamics 365 Finance and Operations Development Tools in Visual Studio 2019

 Introduction:

Dynamics 365 Finance and Operations (D365 FO) is a robust enterprise resource planning (ERP) solution that empowers businesses to streamline their financial, supply chain, and operational processes. To develop and customize solutions for D365 FO, developers often rely on Visual Studio as their primary Integrated Development Environment (IDE). In this guide, we'll walk you through the process of installing the D365 FO development tools in Visual Studio 2019, enabling you to seamlessly create and extend your D365 FO applications.


Prerequisites:

Before you begin the installation process, make sure you have the following prerequisites in place:


Dynamics 365 Finance and Operations Environment: You must have access to a D365 FO environment for development purposes.


Visual Studio 2019: Ensure that you have Visual Studio 2019 installed on your machine. You can download it from the official Visual Studio website.


Administrative Privileges: You need administrative privileges on your computer to install the software.


Installation Steps:

Follow these steps to install the Dynamics 365 Finance and Operations development tools in Visual Studio 2019:


Step 1: Download the Dynamics 365 Unified Operations Platform Installer:


Navigate to the Microsoft Download Center or the CustomerSource portal (if you have access).

Search for the "Dynamics 365 Unified Operations Platform Installer."

Download the installer executable file.

Step 2: Run the Installer:


Locate the downloaded executable file and run it as an administrator.

The installer will perform an initial check of prerequisites and guide you through the installation process.

Step 3: Specify Installation Location:


Choose the installation location for the tools on your machine. You can opt for the default installation path or specify a custom location.

Step 4: Select Components:


The installer will present a list of components to install. Choose the "Developer tools" or equivalent option related to D365 FO development.

You may also be prompted to select additional components based on your project requirements.

Step 5: Configure Visual Studio Integration:


During the installation process, the installer will ask you to configure integration with Visual Studio 2019.

Ensure that you have Visual Studio 2019 selected in the list of supported IDEs.

Step 6: Configure D365 FO Environment:


Provide the necessary configuration details for your D365 FO environment, including the URL and credentials.

This step enables the development tools to connect with your D365 FO instance for seamless development and debugging.

Step 7: Install and Complete:


Review your installation settings and confirm the installation.

The installer will proceed to install the selected components and configure the necessary integrations.

Step 8: Verify Installation:


Once the installation is complete, open Visual Studio 2019.

Create a new Dynamics 365 Finance and Operations project to verify that the development tools are correctly installed.

Conclusion:

Congratulations! You've successfully installed the Dynamics 365 Finance and Operations development tools in Visual Studio 2019. With these tools at your disposal, you're well-equipped to create, customize, and extend solutions for your D365 FO environment. Remember to keep your development tools up-to-date and explore the vast range of capabilities D365 FO offers to enhance your ERP development experience. Happy coding!

Monday 17 July 2023

Multi-Select Lookup on a Form with X++ Code D365 FO

Multi-Select Lookup on a Form with X++ Code


Introduction:

In today's fast-paced digital world, efficient data entry is crucial for businesses to streamline their operations. One common requirement is the ability to select multiple values from a lookup on a form. In this blog post, we will explore how to implement a multi-select lookup functionality on a form using X++ code. By the end of this article, you'll have the knowledge to enhance your forms with this powerful feature, making data entry a breeze.


Step 1: Setting up the Form

    1.Let's add one dialogue form

 

Step 2: Adding the Multi-Select Lookup Control

    1. add a string control 

     2.  add ok and cancel buttons



Step 3: Populating the Lookup Values

        1. override the control Lookup method


  1. declare Global variable for mult-select 
  2. SysLookupMultiSelectCtrl mltSelectCtrl;

 public void lookup()

        {

           

            Query query = new Query();

            QueryBuildDataSource qbd;

            qbd = query.addDataSource(TableNum(yourTable));

            qbd.addSelectionField(FieldNum(yourTable,Field1));

            qbd.addSelectionField(FieldNum(yourTable,Field2));

           

            qbd.clearRanges();

           

            mltSelectCtrl = SysLookupMultiSelectCtrl::constructWithQuery(this.formRun(),this,query);

        }


Step 4: Selected values 

  1. override the OK Click method, in the below method we are just displaying the selected values.

[Control("CommandButton")]

    class OkButton

    {

        public void clicked()

        {

            container sRecid;

            int i;

            

super();


            sRecid = mltSelectCtrl.get();

           

           for(i = 1; i <= conLen(sRecid) ; i++)

            {

                info(strFmt("selected %1 ", conPeek(sRecid,i)));

            }  


    }

How to: Refresh the Calling Form after Dialog Form action.


It is a very common scenario, where we need to refresh the data of a calling from, when you open a dialog or drop dialog.

To achieve this, we need to Override the CloseOk method of the Dialog form. below is the code for the same.

public void closeOk()

    {

        FormRun formRun;

        List dsList;

        ListEnumerator dsListEnumerator;

        FormDataSource formDS;


        super();


        // Get an instance of the calling form.

        formRun = element.args().caller();


        // If the caller is a form, find and refresh the specified root data source.

        if(formRun)

        {

            dsList = formRun.rootFormDataSources();


            if(dsList && dsList.elements() > 0)

            {

                dsListEnumerator = dsList.getEnumerator();


                while(dsListEnumerator.moveNext())

                {

                    formDS = dsListEnumerator.current();

                    formDS.research(true);

                }

            }

        }

    } 

Thursday 15 June 2023

D365 Visual studio (VS) missing Dynamics 365 FO extension

 This blog is to show how to install Dynamics 365 FO extension.

Recently we has an issue in one of the dev boxes, where the Dynamics 365 FO extension was missing, and here is what we have done to resolve the issue.


we can find the Dynamics 365 FO installer in the path 

K:\DeployablePackages\8eadd66c-f069-43f7-ae9f-8834c1a75cde\DevToolsService\Scripts

Run the installer after closing VS if open. 



This will install the Dynamics 365 FO extension. 


Wednesday 14 June 2023

Structured Query language (SQL)

 

1. Create database

create database sample2

2. Use the database

use sample2

3. Create table

create table customer

(

customerid int identity(1,1) primary key,

customernumber int not null unique check (customernumber>0),

lastname varchar(30) not null,

firstname varchar(30) not null,

areacode int default 71000,

address varchar(50),

country varchar(50) default 'Malaysia'

)

4. Insert values into table

insert into customer values

(100,'Fang Ying','Sham','418999','sdadasfdfd',default),

(200,'Mei Mei','Tan',default,'adssdsadsd','Thailand'),

(300,'Albert','John',default,'dfdsfsdf',default)

5. Display record from table

-- display all records

select * from customer

-- display particular columns

select customerid, customernumber, lastname, firstname

from customer

6. Add new column to table

alter table customer

add phonenumber varchar(20)

7. Add values to newly added column/ Update table

update customer set phonenumber='1234545346' where

customerid=1

update customer set phonenumber='45554654' where

customerid=2

8. Delete a column

alter table customer

drop column phonenumber

9. Delete record from table

--if not put ‘where’, will

delete all record

delete

from customer

where country='Thailand'

10. Delete table

drop table customer

11. Change data type

alter table customer

alter column phonenumber varchar(10)

12. Check what table inside

select * from information_schema.tables

13. View specific row

--top: show only the first two

select top 2 * from customer

--top 40 percent: also means show the first two

select top 40 percent * from customer

14. View specific column

--sort result (by default is ascending)

select customerfirstname, customerlastname from customer

order by customerlastname desc

select customerfirstname, customerlastname from customer

order by 4, 2, 3 desc -- Order By Based on column no. without typing column

name

--distinct: only show unique value

select distinct customerlastname from customer

order by customerlastname

15. Save table to another table

--into file_name: save result in another table (BASE TABLE)

select distinct customerlastname into temp

from customer

order by customerlastname

select * from temp --see the table (data type will remain)

16. Like (search something)

-- (underscore sign) _ is only specific for one character only

-- (percent sign) % represents zero, one, or multiple characters

select * from customer

where customerlastname like '_r%'

17. In (search something)

-- search multiple items

select * from customer

where customerlastname in ('Brown', ‘Michael’, ’Jim’)

18. > (search something)

select * from customer where customerlastname > 'Brown' or customerlastname>'Cross'

19. <> (Not Equal)

select * from customer

where customerlastname <> 'Brown'

20. IS NULL

-- check null values

select * from customer

where customerlastname IS NULL

21. IS NOT NULL

select * from customer

where customerlastname IS NOT NULL

22. between

select * from sale

where saleunitprice between 5 and 10 --not include 5 & 10

23. count

-- returns the number of rows in a table

-- AS means aliasing, temporary giving name to a column/ table

select count(*) as [Number of Records] from customer

where customerfirstname like 'B%'

24. sum

select sale.employeeid ,EmployeeFirstName, EmployeeLastName , count(*) as

[Number of order] ,

sum(salequantity) as [Total Quantity]

from sale,employee

where sale.employeeid = employee.employeeid

group by sale.employeeid ,EmployeeFirstName, EmployeeLastName

25. count month

select month(saledate) as [Month], count ( * ) as [Number of sale],

sum(salequantity*saleunitprice) as [Total Amount]

from sale

group by month(saledate)

26. Max/Min/Average

SELECT MAX(Salary)

FROM EmployeeSalary

27. having

SELECT JobTitle, COUNT(JobTitle)

FROM EmployeeDemographics ED

JOIN EmployeeSalary ES

 ON ED.EmployeeID = ES.EmployeeID

GROUP BY JobTitle

HAVING COUNT(JobTitle) > 1

SELECT JobTitle, AVG(Salary)

FROM EmployeeDemographics ED

JOIN EmployeeSalary ES

 ON ED.EmployeeID = ES.EmployeeID

GROUP BY JobTitle

HAVING AVG(Salary) > 45000

ORDER BY AVG(Salary)

28. Change data type temporary for use

-- CAST(expression AS datatype(length))

SELECT CAST('2017-08-25 00:00:00.000' AS date)

-- CONVERT(data_type(length), expression, style)

SELECT CONVERT(date,'2017-08-25 00:00:00.000')

29. CASE Statement

SELECT FirstName, LastName, Age,

CASE

 WHEN Age > 30 THEN 'Old'

 WHEN Age BETWEEN 27 AND 30 THEN 'Young'

 ELSE 'Baby'

END

FROM EmployeeDemographics ED

WHERE Age IS NOT NULL

ORDER BY Age

--

SELECT FirstName, LastName, JobTitle, Salary,

CASE

 WHEN JobTitle = 'Salesman' THEN Salary + (Salary *.10)

 WHEN JobTitle = 'Accountant' THEN Salary + (Salary *.05)

 WHEN JobTitle = 'HR' THEN Salary + (Salary *.000001)

 ELSE Salary + (Salary *.03)

END AS SalaryAfterRaise

FROM EmployeeDemographics ED

JOIN EmployeeSalary ES

ON ED.EmployeeID = ES.EmployeeID

30. Partition By --returns a single value for each row

SELECT FirstName, LastName, Gender, Salary,

COUNT(Gender) OVER (PARTITION BY Gender) AS TotalGender

FROM EmployeeDemographics ED

JOIN EmployeeSalary ES

ON ED.EmployeeID = ES.EmployeeID

31. String Functions

-- Remove space

Select EmployeeID, TRIM(EmployeeID) AS IDTRIM

FROM EmployeeErrors

Select EmployeeID, RTRIM(EmployeeID) as IDRTRIM

FROM EmployeeErrors

Select EmployeeID, LTRIM(EmployeeID) as IDLTRIM

FROM EmployeeErrors

-- Replace

Select LastName, REPLACE(LastName, '- Fired', '') as

LastNameFixed

FROM EmployeeErrors

-- Substring

Select Substring(err.FirstName,1,3),

Substring(dem.FirstName,1,3), Substring(err.LastName,1,3),

Substring(dem.LastName,1,3)

FROM EmployeeErrors err

JOIN EmployeeDemographics dem

 on Substring(err.FirstName,1,3) =

Substring(dem.FirstName,1,3)

 and Substring(err.LastName,1,3) =

Substring(dem.LastName,1,3)

-- UPPER and LOWER CASE

Select firstname, LOWER(firstname)

from EmployeeErrors

Select Firstname, UPPER(FirstName)

from EmployeeErrors"

32. Stored Procedure

CREATE PROCEDURE Temp_Employee

@JobTitle nvarchar(100)

AS

DROP TABLE IF EXISTS #temp_employee

Create table #temp_employee (

JobTitle varchar(100),

EmployeesPerJob int ,

AvgAge int,

AvgSalary int

)

Insert into #temp_employee

SELECT JobTitle, Count(JobTitle), Avg(Age), AVG(salary)

FROM EmployeeDemographics emp

JOIN EmployeeSalary sal

 ON emp.EmployeeID = sal.EmployeeID

where JobTitle = @JobTitle --- make sure to change this in

this script from original above

group by JobTitle

Select *

From #temp_employee

GO;

By Fang Ying, Sham

6

--- only need to run this on next time

EXEC Temp_Employee @JobTitle = 'Salesman'

33. Subquery

-- Subquery in Select

SELECT EmployeeID, Salary, (SELECT AVG(Salary) FROM

EmployeeSalary) AS AllAvgSalary

FROM EmployeeSalary

-- with Partition By

SELECT EmployeeID, Salary, AVG(Salary) OVER () AS

AllAvgSalary

FROM EmployeeSalary

-- Subquery in From

SELECT a.EmployeeID, AllAvgSalary

FROM (SELECT EmployeeID, Salary, AVG(Salary) OVER () AS

AllAvgSalary

 FROM EmployeeSalary) a

ORDER BY a.EmployeeID

 

-- Subquery in Where

SELECT EmployeeID, JobTitle, Salary

FROM EmployeeSalary

WHERE EmployeeID in (SELECT EmployeeID FROM

EmployeeDemographics

 WHERE Age > 30)

SELECT EmployeeID, JobTitle, Salary

FROM EmployeeSalary

WHERE Salary in (SELECT Max(Salary) FROM EmployeeSalary)


1. getting data from multiple tables (explicit join - without using join command)

select * from inventory,sale

where sale.inventoryid=inventory.inventoryid

select

inventoryname,saledate,saleunitprice,salequantity,salequantity*saleunitprice

as [Total amount]

from sale,inventory

where sale.inventoryid=inventory.inventoryid

group by sale.inventoryid,inventoryname,saledate,salequantity,saleunitprice

order by inventoryname

2. getting data from multiple

tables

(implicit join - using join

command)

--inner join

select * from inventory

inner join sale

on sale.inventoryid=inventory.inventoryid

select

inventoryname,saledate,saleunitprice,salequantity,saleunitprice*salequantity

as [Total Amount]

from inventory inner join sale

on sale.inventoryid=inventory.inventoryid

order by inventoryname


 

--full outer join (shows everything)

select sale.inventoryid,inventoryname

from inventory

full outer join sale on

sale.inventoryid=inventory.inventoryid

where sale.inventoryid is NULL

 


 

--left join (might have NULL value, since some inventory might not have sales)

select inventory.inventoryid,inventoryname

from inventory left join sale on

sale.inventoryid=inventory.inventoryid


 

--left join

select inventory.inventoryid,inventoryname

from inventory left join sale on

sale.inventoryid=inventory.inventoryid

where sale.inventoryid is NULL

 


-- without join: use subquery

select inventoryid,inventoryname from inventory

where inventoryid not in (select inventoryid from sale)

 

--right join

select sale.inventoryid,inventoryname

from inventory right join sale on

sale.inventoryid=inventory.inventoryid


3. Self Join --commonly used in processing hierarchy

--inner join

Staff Table

employeeID employeefirstname employeelastname managerID

1001 Tan Mei Ling NULL

1002 Kelvin Koh 1001

1003 Amin Wong 1002

 

select E.employeeID, E.employeefirstname+' '+E.employeelastname as [Full

Name], E.managerID, , M.employeefirstname+' '+M.employeelastname as

[Manager Name]

from staff E

inner join staff M

on E.managerID = M.employeeID

 

 

--left outer join (list all the employees) select E.employeeID, E.employeefirstname+' '+E.employeelastname as [F Name], E.managerID, , M.employeefirstname+' '+M.employeelastname as [Manager Name] from staff E left outer join staff M on E.managerID = M.employeeID

4. Cross Join --generate all combination of records (all possibility

select * from inventory1

cross join inventory2


1. Union

--allow you to combine two tables

together (but the no. of columns &

each column’s data types for 2 tables

must be match)

--don't need common key, only need

common attributes

--merge, not showing duplicate record

select cust_lname,cust_fname from customer

union

select cust_lname,cust_fname from customer_2

2. Union all --merge, but show you everything, even the duplicate record

select cust_lname,cust_fname from customer

union all

select cust_lname,cust_fname from customer_2

3. Intersect

--keep only the rows in common to

both query

--not showing duplicate record

select cust_lname,cust_fname from customer

intersect

select cust_lname,cust_fname from customer_2

 

select c.cust_lname,c.cust_fname from customer c,customer_2 c2

where c.cust_lname=c2.cust_lname and c.cust_fname=c2.cust_fname

4. Except

--generate only the records that are

unique to

the CUSTOMER table

select cust_lname,cust_fname from customer

except

select cust_lname,cust_fname from customer_2

 

--use subquery

select cust_lname,cust_fname from customer

where(cust_lname) not in

(select cust_lname from customer_2) and

(cust_fname) not in

(select cust_fname from customer_2)

Table & View

1. view table

(view will be updated when

update base)

--view is a result set of SQL

statements, exists only for a

single query

create view CustomerView as

select customerfirstname+' '+customerlastname as [Customer Name] ,

customerphonenumber,

inventoryname,saledate,salequantity,saleunitprice,salequantity*saleunitprice

as [Total Amount]

from customer inner join sale on customer.customerid=sale.customerid inner

join inventory

on sale.inventoryid=inventory.inventoryid

 


2. Temp table (temp will NOT be updated when update base) --a single hashtag (#) sign must be added in front of their names --used to store data temporarily, physically created in the Tempdb database --can perform CRUD, join, and some other operations like the persistent database tables

DROP TABLE IF EXISTS #temp_Employee

Create table #temp_Employee (

JobTitle varchar(100),

EmployeesPerJob int,

AvgAge int,

AvgSalary int

)

Insert INTO #temp_Employee

SELECT JobTitle, Count(JobTitle), Avg(Age), AVG(salary)

FROM EmployeeDemographics emp

JOIN EmployeeSalary sal

 ON emp.EmployeeID = sal.EmployeeID

group by JobTitle

SELECT * FROM #temp_Employee

3. CTE (Common Table Expression) --create temporary result set which is used to manipulate the complex sub-queries data --created in memory rather than Tempdb database, so cannot create any index on CTE.

WITH CTE_Employee AS

(

SELECT FirstName, LastName, Gender, Salary,

COUNT(Gender) OVER (PARTITION BY Gender) AS TotalGender

FROM EmployeeDemographics ED

JOIN EmployeeSalary ES

ON ED.EmployeeID = ES.EmployeeID

WHERE Salary > '45000'

)

SELECT FirstName, LastName, Gender, TotalGender

FROM CTE_Employee

WHERE TotalGender = (SELECT MIN(TotalGender) FROM CTE_Employee)

4. Duplicate Table

select customerfirstname+' '+customerlastname as [Customer Name] ,

customerphonenumber,

inventoryname,saledate,salequantity,saleunitprice,salequantity*saleunitprice

as [Total Amount] into customerRec

from customer inner join sale on customer.customerid=sale.customerid inner

join inventory

on sale.inventoryid=inventory.inventoryid

order by customerfirstname +' '+ customerlastname,inventoryname

SQL RANKS

1. ROW_NUMBER()

--get a unique sequential number for each row

--get different ranks for the row having similar values

SELECT *,

 ROW_NUMBER() OVER(ORDER BY Salary DESC) SalaryRank

FROM EmployeeSalary

2. RANK()

--specify rank for each row in the result set

--use PARTITION BY to performs calculation on each group

--each subset get rank as per Salary in descending order

USING PARTITION BY

SELECT *,

 RANK() OVER(PARTITION BY JobTitle ORDER BY Salary DESC)

SalaryRank

FROM EmployeeSalary

ORDER BY JobTitle, SalaryRank

 


NOT USING PARTITION BY

-- get SAME ranks for the row having similar values

SELECT *,

 RANK() OVER(ORDER BY Salary DESC) SalaryRank

FROM EmployeeSalary

ORDER BY SalaryRank

3. DENSE_RANK()

-- if have duplicate values, SQL assigns different ranks to those rows.

-- will get the same rank for duplicate or similar values

SELECT *,

 DENSE_RANK() OVER(ORDER BY Salary DESC) SalaryRank

FROM EmployeeSalary

ORDER BY SalaryRank

3. Split by delimiter SUBSTRING(string, start, length) CHARINDEX(substring, string, start) LEN(string)

 

 

SELECT PropertyAddress,

SUBSTRING(PropertyAddress, 1, CHARINDEX(',',

PropertyAddress) -1 ) as Address

, SUBSTRING(PropertyAddress, CHARINDEX(',',

PropertyAddress) + 1 , LEN(PropertyAddress)) as City

From NashvilleHousing

 

ALTER TABLE NashvilleHousing

Add PropertySplitAddress Nvarchar(255);

ALTER TABLE NashvilleHousing

Add PropertySplitCity Nvarchar(255);

 

Update NashvilleHousing

SET PropertySplitAddress = SUBSTRING(PropertyAddress, 1,

CHARINDEX(',', PropertyAddress) -1 )

Update NashvilleHousing

SET PropertySplitCity = SUBSTRING(PropertyAddress,

CHARINDEX(',', PropertyAddress) + 1 , LEN(PropertyAddress))

PARSENAME('object_name'

, object_piece)

--numbering works from

right to left

REPLACE(string, old_string,

new_string)

Select OwnerAddress,

PARSENAME(REPLACE(OwnerAddress, ',', '.') , 3)

,PARSENAME(REPLACE(OwnerAddress, ',', '.') , 2)

,PARSENAME(REPLACE(OwnerAddress, ',', '.') , 1)

From NashvilleHousing

 

ALTER TABLE NashvilleHousing

Add OwnerSplitAddress Nvarchar(255);

ALTER TABLE NashvilleHousing

Add OwnerSplitCity Nvarchar(255);

ALTER TABLE NashvilleHousing

Add OwnerSplitState Nvarchar(255);

Update NashvilleHousing

SET OwnerSplitAddress = PARSENAME(REPLACE(OwnerAddress,

',', '.') , 3)

Update NashvilleHousing

SET OwnerSplitCity = PARSENAME(REPLACE(OwnerAddress, ',',

'.') , 2)

Update NashvilleHousing

SET OwnerSplitState = PARSENAME(REPLACE(OwnerAddress, ',',

'.') , 1)

5. Remove duplicate records

WITH RowNumCTE AS(

Select *,

ROW_NUMBER() OVER (

PARTITION BY ParcelID,

PropertyAddress,

SalePrice,

SaleDate,

LegalReference

ORDER BY UniqueID) as row_num

From NashvilleHousing

order by ParcelID

)

--DELETE

Select * From RowNumCTE

Where row_num > 1

Order by PropertyAddress

 

 

 

Update NuGet package to new MS D365FO version

1. Import the NuGet package files from LCS for that particular version please take the PU version files only. a. Goto LCS-->Asset Libra...