When jumping from one project to another, it can be useful to be able to compare common code structures.
I couldn’t find anything like this out there, so here it is magically created.
Contents:
Common Code Structures
Working with Dates
Window Functions
Error Handling
Casting
Joining Tables
CTE (Common Table Expressions)
Common Code Structures
Topic | SQL Server | Snowflake | BigQuery |
---|---|---|---|
Select & Filtering | SELECT TOP 10 * FROM Sales WHERE Amount > 1000; |
SELECT * FROM Sales WHERE Amount > 1000 LIMIT 10; |
SELECT * FROM `project.dataset.Sales` WHERE Amount > 1000 LIMIT 10; |
String Functions | SELECT LEFT(CustomerName, 5), LEN(CustomerName) FROM Customers; |
SELECT LEFT(CustomerName, 5), LENGTH(CustomerName) FROM Customers; |
SELECT SUBSTR(CustomerName, 1, 5), LENGTH(CustomerName) FROM `project.dataset.Customers`; |
Date Functions | SELECT GETDATE() AS CurrentDate, DATEADD(DAY, 7, GETDATE()); |
SELECT CURRENT_DATE, DATEADD(DAY, 7, CURRENT_DATE); |
SELECT CURRENT_DATE(), DATE_ADD(CURRENT_DATE(), INTERVAL 7 DAY); |
Joins | SELECT c.CustomerName, o.OrderID FROM Customers c INNER JOIN Orders o ON c.CustomerID = o.CustomerID; |
SELECT c.CustomerName, o.OrderID FROM Customers c JOIN Orders o ON c.CustomerID = o.CustomerID; |
SELECT c.CustomerName, o.OrderID FROM `project.dataset.Customers` c JOIN `project.dataset.Orders` o ON c.CustomerID = o.CustomerID; |
Aggregations & Group By | SELECT CustomerID, SUM(Amount) AS TotalAmount FROM Sales GROUP BY CustomerID HAVING SUM(Amount) > 1000; |
SELECT CustomerID, SUM(Amount) AS TotalAmount FROM Sales GROUP BY CustomerID HAVING SUM(Amount) > 1000; |
SELECT CustomerID, SUM(Amount) AS TotalAmount FROM `project.dataset.Sales` GROUP BY CustomerID HAVING SUM(Amount) > 1000; |
Window Functions | SELECT CustomerID, SUM(Amount) OVER (PARTITION BY CustomerID) AS TotalByCustomer FROM Sales; |
SELECT CustomerID, SUM(Amount) OVER (PARTITION BY CustomerID) AS TotalByCustomer FROM Sales; |
SELECT CustomerID, SUM(Amount) OVER (PARTITION BY CustomerID) AS TotalByCustomer FROM `project.dataset.Sales`; |
Creating Tables | CREATE TABLE Customers ( CustomerID INT PRIMARY KEY, CustomerName NVARCHAR(100) ); |
CREATE TABLE Customers ( CustomerID INT PRIMARY KEY, CustomerName STRING ); |
CREATE TABLE dataset.Customers ( CustomerID INT64, CustomerName STRING ); |
Insert | INSERT INTO Customers (CustomerID, CustomerName) VALUES (1, 'John Doe'); |
INSERT INTO Customers (CustomerID, CustomerName) VALUES (1, 'John Doe'); |
INSERT INTO dataset.Customers (CustomerID, CustomerName) VALUES (1, 'John Doe'); |
Update | UPDATE Customers SET CustomerName = 'Jane Doe' WHERE CustomerID = 1; |
UPDATE Customers SET CustomerName = 'Jane Doe' WHERE CustomerID = 1; |
UPDATE dataset.Customers SET CustomerName = 'Jane Doe' WHERE CustomerID = 1; |
Delete | DELETE FROM Customers WHERE CustomerID = 1; |
DELETE FROM Customers WHERE CustomerID = 1; |
DELETE FROM dataset.Customers WHERE CustomerID = 1; |
Case When Statements | SELECT OrderID, CASE WHEN Amount >= 1000 THEN 'High' WHEN Amount >= 500 THEN 'Medium' ELSE 'Low' END AS OrderCategory FROM Sales; |
SELECT OrderID, CASE WHEN Amount >= 1000 THEN 'High' WHEN Amount >= 500 THEN 'Medium' ELSE 'Low' END AS OrderCategory FROM Sales; |
SELECT OrderID, CASE WHEN Amount >= 1000 THEN 'High' WHEN Amount >= 500 THEN 'Medium' ELSE 'Low' END AS OrderCategory FROM `project.dataset.Sales`; |
Start of Month | SELECT OrderDate, DATEADD(MONTH, DATEDIFF(MONTH, 0, OrderDate), 0) AS StartOfMonth FROM Orders; |
SELECT OrderDate, DATE_TRUNC('MONTH', OrderDate) AS StartOfMonth FROM Orders; |
SELECT OrderDate, DATE_TRUNC(OrderDate, MONTH) AS StartOfMonth FROM `project.dataset.Orders`; |
End of Month | SELECT OrderDate, EOMONTH(OrderDate) AS EndOfMonth FROM Orders; |
SELECT OrderDate, LAST_DAY(OrderDate, 'MONTH') AS EndOfMonth FROM Orders; |
SELECT OrderDate, LAST_DAY(OrderDate, MONTH) AS EndOfMonth FROM `project.dataset.Orders`; |
Null Handling | SELECT CustomerID, COALESCE(CustomerName, 'Unknown') AS SafeName FROM Customers; |
SELECT CustomerID, COALESCE(CustomerName, 'Unknown') AS SafeName FROM Customers; |
SELECT CustomerID, COALESCE(CustomerName, 'Unknown') AS SafeName FROM `project.dataset.Customers`; |
Conditional Aggregation | SELECT CustomerID, SUM(CASE WHEN Amount > 1000 THEN Amount ELSE 0 END) AS HighValueSales FROM Sales GROUP BY CustomerID; |
SELECT CustomerID, SUM(CASE WHEN Amount > 1000 THEN Amount ELSE 0 END) AS HighValueSales FROM Sales GROUP BY CustomerID; |
SELECT CustomerID, SUM(CASE WHEN Amount > 1000 THEN Amount ELSE 0 END) AS HighValueSales FROM `project.dataset.Sales` GROUP BY CustomerID; |
Date Difference | SELECT OrderID, DATEDIFF(DAY, OrderDate, ShippedDate) AS DaysToShip FROM Orders; |
SELECT OrderID, DATEDIFF(DAY, OrderDate, ShippedDate) AS DaysToShip FROM Orders; |
SELECT OrderID, DATE_DIFF(ShippedDate, OrderDate, DAY) AS DaysToShip FROM `project.dataset.Orders`; |
Working with Dates
Date Topic | SQL Server | Snowflake | BigQuery |
---|---|---|---|
Build Date from Parts | SELECT DATEFROMPARTS(2025, 10, 3) AS d; |
SELECT DATE_FROM_PARTS(2025, 10, 3) AS d; |
SELECT DATE(2025, 10, 3) AS d; |
Parse Date from String | SELECT TRY_CONVERT(date, '03/10/2025', 103); -- DD/MM/YYYY SELECT CONVERT(date, '2025-10-03', 23); -- ISO |
SELECT TO_DATE('03/10/2025', 'DD/MM/YYYY'); SELECT TO_DATE('2025-10-03'); |
SELECT PARSE_DATE('%d/%m/%Y','03/10/2025'); SELECT DATE '2025-10-03'; |
Current Date / Timestamp | SELECT CAST(GETDATE() AS date) AS current_date, GETDATE() AS current_datetime; |
SELECT CURRENT_DATE AS current_date, CURRENT_TIMESTAMP AS current_ts; |
SELECT CURRENT_DATE() AS current_date, CURRENT_TIMESTAMP() AS current_ts; |
Start of Month | SELECT DATEADD(MONTH, DATEDIFF(MONTH, 0, OrderDate), 0) FROM Orders; |
SELECT DATE_TRUNC('MONTH', OrderDate) FROM Orders; |
SELECT DATE_TRUNC(OrderDate, MONTH) FROM `project.dataset.Orders`; |
End of Month | SELECT EOMONTH(OrderDate) FROM Orders; |
SELECT LAST_DAY(OrderDate, 'MONTH') FROM Orders; |
SELECT LAST_DAY(OrderDate, MONTH) FROM `project.dataset.Orders`; |
Add Days | SELECT DATEADD(DAY, 7, OrderDate) FROM Orders; |
SELECT DATEADD(DAY, 7, OrderDate) FROM Orders; |
SELECT DATE_ADD(OrderDate, INTERVAL 7 DAY) FROM `project.dataset.Orders`; |
Add Months | SELECT DATEADD(MONTH, 3, OrderDate) FROM Orders; |
SELECT DATEADD(MONTH, 3, OrderDate) FROM Orders; |
SELECT DATE_ADD(OrderDate, INTERVAL 3 MONTH) FROM `project.dataset.Orders`; |
Difference (Days) | SELECT DATEDIFF(DAY, OrderDate, ShippedDate) FROM Orders; |
SELECT DATEDIFF('DAY', OrderDate, ShippedDate) FROM Orders; |
SELECT DATE_DIFF(ShippedDate, OrderDate, DAY) FROM `project.dataset.Orders`; |
Difference (Months) | SELECT DATEDIFF(MONTH, StartDate, EndDate) AS months_between; |
SELECT DATEDIFF('MONTH', StartDate, EndDate) AS months_between; |
SELECT DATE_DIFF(EndDate, StartDate, MONTH) AS months_between; |
Truncate to Week (Week Start) | -- Week starting Sunday SELECT DATEADD(WEEK, DATEDIFF(WEEK, 0, OrderDate), 0) FROM Orders; |
-- ISO week (Mon start) SELECT DATE_TRUNC('WEEK', OrderDate) FROM Orders; |
-- Default WEEK (Sun). Use WEEK(MONDAY) if needed SELECT DATE_TRUNC(OrderDate, WEEK) FROM `project.dataset.Orders`; |
Truncate to Quarter | SELECT DATEADD(QUARTER, DATEDIFF(QUARTER, 0, OrderDate), 0) FROM Orders; |
SELECT DATE_TRUNC('QUARTER', OrderDate) FROM Orders; |
SELECT DATE_TRUNC(OrderDate, QUARTER) FROM `project.dataset.Orders`; |
First Day of Year | SELECT DATEADD(YEAR, DATEDIFF(YEAR, 0, OrderDate), 0) FROM Orders; |
SELECT DATE_TRUNC('YEAR', OrderDate) FROM Orders; |
SELECT DATE_TRUNC(OrderDate, YEAR) FROM `project.dataset.Orders`; |
Last Day of Year | SELECT EOMONTH(DATEFROMPARTS(YEAR(OrderDate), 12, 1)) FROM Orders; |
SELECT LAST_DAY(OrderDate, 'YEAR') FROM Orders; |
SELECT LAST_DAY(OrderDate, YEAR) FROM `project.dataset.Orders`; |
Extract Year / Month / Day | SELECT YEAR(OrderDate) AS y, MONTH(OrderDate) AS m, DAY(OrderDate) AS d FROM Orders; |
SELECT YEAR(OrderDate) AS y, MONTH(OrderDate) AS m, DAY(OrderDate) AS d FROM Orders; |
SELECT EXTRACT(YEAR FROM OrderDate) AS y, EXTRACT(MONTH FROM OrderDate) AS m, EXTRACT(DAY FROM OrderDate) AS d FROM `project.dataset.Orders`; |
Day Name / Weekday | SELECT DATENAME(WEEKDAY, OrderDate) AS day_name, DATEPART(WEEKDAY, OrderDate) AS weekday_num FROM Orders; |
SELECT DAYNAME(OrderDate) AS day_name, DAYOFWEEK(OrderDate) AS weekday_num FROM Orders; |
SELECT FORMAT_DATE('%A', OrderDate) AS day_name, EXTRACT(DAYOFWEEK FROM OrderDate) AS weekday_num FROM `project.dataset.Orders`; |
Between Dates (Inclusive) | SELECT * FROM Orders WHERE OrderDate BETWEEN '2025-10-01' AND '2025-10-31'; |
SELECT * FROM Orders WHERE OrderDate BETWEEN '2025-10-01' AND '2025-10-31'; |
SELECT * FROM `project.dataset.Orders` WHERE OrderDate BETWEEN DATE '2025-10-01' AND DATE '2025-10-31'; |
Last 30 Days Filter | SELECT * FROM Orders WHERE OrderDate >= DATEADD(DAY, -30, CAST(GETDATE() AS date)); |
SELECT * FROM Orders WHERE OrderDate >= DATEADD(DAY, -30, CURRENT_DATE); |
SELECT * FROM `project.dataset.Orders` WHERE OrderDate >= DATE_SUB(CURRENT_DATE(), INTERVAL 30 DAY); |
Window Functions
Window Topic | SQL Server | Snowflake | BigQuery |
---|---|---|---|
Running Total | SELECT CustomerID, OrderDate, Amount, SUM(Amount) OVER ( PARTITION BY CustomerID ORDER BY OrderDate ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW ) AS RunningTotal FROM Sales; |
SELECT CustomerID, OrderDate, Amount, SUM(Amount) OVER ( PARTITION BY CustomerID ORDER BY OrderDate ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW ) AS RunningTotal FROM Sales; |
SELECT CustomerID, OrderDate, Amount, SUM(Amount) OVER ( PARTITION BY CustomerID ORDER BY OrderDate ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW ) AS RunningTotal FROM `project.dataset.Sales`; |
Moving Avg (7 rows) | SELECT OrderDate, Amount, AVG(Amount) OVER ( ORDER BY OrderDate ROWS BETWEEN 6 PRECEDING AND CURRENT ROW ) AS MovAvg7 FROM Sales; |
SELECT OrderDate, Amount, AVG(Amount) OVER ( ORDER BY OrderDate ROWS BETWEEN 6 PRECEDING AND CURRENT ROW ) AS MovAvg7 FROM Sales; |
SELECT OrderDate, Amount, AVG(Amount) OVER ( ORDER BY OrderDate ROWS BETWEEN 6 PRECEDING AND CURRENT ROW ) AS MovAvg7 FROM `project.dataset.Sales`; |
ROW_NUMBER | SELECT *, ROW_NUMBER() OVER ( PARTITION BY CustomerID ORDER BY OrderDate DESC ) AS rn FROM Sales; |
SELECT *, ROW_NUMBER() OVER ( PARTITION BY CustomerID ORDER BY OrderDate DESC ) AS rn FROM Sales; |
SELECT *, ROW_NUMBER() OVER ( PARTITION BY CustomerID ORDER BY OrderDate DESC ) AS rn FROM `project.dataset.Sales`; |
RANK | SELECT CustomerID, Amount, RANK() OVER (PARTITION BY CustomerID ORDER BY Amount DESC) AS rnk FROM Sales; |
SELECT CustomerID, Amount, RANK() OVER (PARTITION BY CustomerID ORDER BY Amount DESC) AS rnk FROM Sales; |
SELECT CustomerID, Amount, RANK() OVER (PARTITION BY CustomerID ORDER BY Amount DESC) AS rnk FROM `project.dataset.Sales`; |
DENSE_RANK | SELECT CustomerID, Amount, DENSE_RANK() OVER (PARTITION BY CustomerID ORDER BY Amount DESC) AS drnk FROM Sales; |
SELECT CustomerID, Amount, DENSE_RANK() OVER (PARTITION BY CustomerID ORDER BY Amount DESC) AS drnk FROM Sales; |
SELECT CustomerID, Amount, DENSE_RANK() OVER (PARTITION BY CustomerID ORDER BY Amount DESC) AS drnk FROM `project.dataset.Sales`; |
NTILE (Quartiles) | SELECT CustomerID, Amount, NTILE(4) OVER (ORDER BY Amount DESC) AS quartile FROM Sales; |
SELECT CustomerID, Amount, NTILE(4) OVER (ORDER BY Amount DESC) AS quartile FROM Sales; |
SELECT CustomerID, Amount, NTILE(4) OVER (ORDER BY Amount DESC) AS quartile FROM `project.dataset.Sales`; |
LAG (Prev Row) | SELECT OrderDate, Amount, LAG(Amount, 1) OVER (ORDER BY OrderDate) AS PrevAmt FROM Sales; |
SELECT OrderDate, Amount, LAG(Amount, 1) OVER (ORDER BY OrderDate) AS PrevAmt FROM Sales; |
SELECT OrderDate, Amount, LAG(Amount, 1) OVER (ORDER BY OrderDate) AS PrevAmt FROM `project.dataset.Sales`; |
LEAD (Next Row) | SELECT OrderDate, Amount, LEAD(Amount, 1) OVER (ORDER BY OrderDate) AS NextAmt FROM Sales; |
SELECT OrderDate, Amount, LEAD(Amount, 1) OVER (ORDER BY OrderDate) AS NextAmt FROM Sales; |
SELECT OrderDate, Amount, LEAD(Amount, 1) OVER (ORDER BY OrderDate) AS NextAmt FROM `project.dataset.Sales`; |
FIRST_VALUE | SELECT OrderDate, Amount, FIRST_VALUE(Amount) OVER ( ORDER BY OrderDate ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW ) AS FirstAmt FROM Sales; |
SELECT OrderDate, Amount, FIRST_VALUE(Amount) OVER ( ORDER BY OrderDate ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW ) AS FirstAmt FROM Sales; |
SELECT OrderDate, Amount, FIRST_VALUE(Amount) OVER ( ORDER BY OrderDate ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW ) AS FirstAmt FROM `project.dataset.Sales`; |
LAST_VALUE* | SELECT OrderDate, Amount, LAST_VALUE(Amount) OVER ( ORDER BY OrderDate ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING ) AS LastAmt FROM Sales; |
SELECT OrderDate, Amount, LAST_VALUE(Amount) OVER ( ORDER BY OrderDate ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING ) AS LastAmt FROM Sales; |
SELECT OrderDate, Amount, LAST_VALUE(Amount) OVER ( ORDER BY OrderDate ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING ) AS LastAmt FROM `project.dataset.Sales`; |
PERCENT_RANK() | SELECT Amount, PERCENT_RANK() OVER (ORDER BY Amount) AS pct_rank FROM Sales; |
SELECT Amount, PERCENT_RANK() OVER (ORDER BY Amount) AS pct_rank FROM Sales; |
SELECT Amount, PERCENT_RANK() OVER (ORDER BY Amount) AS pct_rank FROM `project.dataset.Sales`; |
CUME_DIST() | SELECT Amount, CUME_DIST() OVER (ORDER BY Amount) AS cume FROM Sales; |
SELECT Amount, CUME_DIST() OVER (ORDER BY Amount) AS cume FROM Sales; |
SELECT Amount, CUME_DIST() OVER (ORDER BY Amount) AS cume FROM `project.dataset.Sales`; |
Share of Total | SELECT CustomerID, Amount, Amount * 1.0 / SUM(Amount) OVER ( PARTITION BY CustomerID ) AS ShareOfCust FROM Sales; |
SELECT CustomerID, Amount, Amount / SUM(Amount) OVER ( PARTITION BY CustomerID ) AS ShareOfCust FROM Sales; |
SELECT CustomerID, Amount, Amount / SUM(Amount) OVER ( PARTITION BY CustomerID ) AS ShareOfCust FROM `project.dataset.Sales`; |
COUNT Over Window | SELECT CustomerID, OrderDate, COUNT(*) OVER ( PARTITION BY CustomerID ORDER BY OrderDate ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW ) AS CntToDate FROM Sales; |
SELECT CustomerID, OrderDate, COUNT(*) OVER ( PARTITION BY CustomerID ORDER BY OrderDate ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW ) AS CntToDate FROM Sales; |
SELECT CustomerID, OrderDate, COUNT(*) OVER ( PARTITION BY CustomerID ORDER BY OrderDate ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW ) AS CntToDate FROM `project.dataset.Sales`; |
Distinct Count in Window | -- COUNT(DISTINCT) OVER is not supported. -- Workaround: distinct per partition via DENSE_RANK. WITH x AS ( SELECT CustomerID, ProductID, DENSE_RANK() OVER ( PARTITION BY CustomerID ORDER BY ProductID ) AS r FROM Sales ) SELECT CustomerID, MAX(r) AS DistinctProducts FROM x GROUP BY CustomerID; |
-- COUNT(DISTINCT) OVER not supported in Snowflake windows. -- Use DENSE_RANK or COUNT(DISTINCT) without OVER at final grouping. |
-- COUNT(DISTINCT) OVER not supported in BigQuery windows. -- Use DENSE_RANK or COUNT(DISTINCT) at GROUP BY level. |
Error Handling
Error Handling Topic | SQL Server | Snowflake | BigQuery |
---|---|---|---|
Replace NULL with Default | SELECT ISNULL(Amount, 0) AS SafeAmt, COALESCE(CustomerName, 'Unknown') AS SafeName FROM Sales; |
SELECT IFNULL(Amount, 0) AS SafeAmt, COALESCE(CustomerName, 'Unknown') AS SafeName FROM Sales; |
SELECT IFNULL(Amount, 0) AS SafeAmt, COALESCE(CustomerName, 'Unknown') AS SafeName FROM `project.dataset.Sales`; |
Safe Division by Zero | SELECT CASE WHEN Denominator = 0 THEN NULL ELSE Numerator * 1.0 / Denominator END AS Ratio FROM Data; |
SELECT DIV0(Numerator, Denominator) AS Ratio FROM Data; |
SELECT SAFE_DIVIDE(Numerator, Denominator) AS Ratio FROM `project.dataset.Data`; |
Safe Cast / Conversion | SELECT TRY_CAST(Value AS INT) AS SafeInt FROM RawData; |
SELECT TRY_TO_NUMBER(Value) AS SafeInt FROM RawData; |
SELECT SAFE_CAST(Value AS INT64) AS SafeInt FROM `project.dataset.RawData`; |
Null If | SELECT NULLIF(Amount, 0) AS NullIfZero FROM Sales; |
SELECT NULLIF(Amount, 0) AS NullIfZero FROM Sales; |
SELECT NULLIF(Amount, 0) AS NullIfZero FROM `project.dataset.Sales`; |
Error Catch / Try | BEGIN TRY SELECT 1/0; END TRY BEGIN CATCH SELECT ERROR_MESSAGE(); END CATCH; |
-- Snowflake doesn’t have TRY/CATCH in SQL. -- Use TRY_* functions (TRY_TO_NUMBER, TRY_CAST) to avoid errors. |
-- BigQuery doesn’t support TRY/CATCH in SQL. -- Use SAFE_CAST, SAFE_DIVIDE, IFERROR(expr, alt) in some contexts. |
IfError Style (Return fallback if error) | -- Not native in T-SQL. -- Wrap in TRY/CATCH or use CASE + TRY_CAST. |
SELECT TRY_TO_NUMBER(Value, 0) AS SafeVal; |
SELECT IFERROR(1/0, NULL) AS SafeVal; |
Casting
Casting Topic | SQL Server | Snowflake | BigQuery |
---|---|---|---|
Basic CAST | SELECT CAST(Amount AS DECIMAL(12,2)) AS amt_dec; |
SELECT CAST(Amount AS NUMBER(12,2)) AS amt_dec; |
SELECT CAST(Amount AS NUMERIC(12,2)) AS amt_dec; |
Alt Syntax | SELECT CONVERT(DECIMAL(12,2), Amount) AS amt_dec; |
SELECT Amount::NUMBER(12,2) AS amt_dec; |
-- Standard CAST only (no ::) SELECT CAST(Amount AS NUMERIC(12,2)); |
Safe Cast | SELECT TRY_CAST(Value AS INT) AS safe_int; |
SELECT TRY_TO_NUMBER(Value) AS safe_num; |
SELECT SAFE_CAST(Value AS INT64) AS safe_int; |
String → INT | SELECT TRY_CONVERT(INT, '123') AS i; |
SELECT TRY_TO_NUMBER('123')::INT AS i; |
SELECT SAFE_CAST('123' AS INT64) AS i; |
String → DECIMAL | SELECT TRY_CAST('123.45' AS DECIMAL(10,2)) AS d; |
SELECT TRY_TO_DECIMAL('123.45',10,2) AS d; |
SELECT SAFE_CAST('123.45' AS NUMERIC(10,2)) AS d; |
String → DATE (format) | -- DD/MM/YYYY SELECT TRY_CONVERT(date, '03/10/2025', 103); |
SELECT TO_DATE('03/10/2025','DD/MM/YYYY'); |
SELECT PARSE_DATE('%d/%m/%Y', '03/10/2025'); |
String → TIMESTAMP | SELECT TRY_CONVERT(datetime2, '2025-10-03T14:05:00Z', 127); |
SELECT TO_TIMESTAMP_TZ('2025-10-03T14:05:00Z'); |
SELECT TIMESTAMP('2025-10-03T14:05:00Z'); |
Epoch Seconds → TS | SELECT DATEADD(SECOND, 1696341900, '1970-01-01'); |
SELECT TO_TIMESTAMP(1696341900); -- seconds |
SELECT TIMESTAMP_SECONDS(1696341900); |
Time Zone Convert | SELECT (YourDT AT TIME ZONE 'UTC') AT TIME ZONE 'Europe/Malta' AS local_dt; |
SELECT CONVERT_TIMEZONE('UTC','Europe/Malta', YourTS) AS local_ts; |
-- Convert UTC timestamp to Europe/Malta datetime SELECT DATETIME(TIMESTAMP(YourDT), 'Europe/Malta') AS local_dt; |
String → BOOLEAN | -- No direct parse; map via CASE SELECT CASE WHEN LOWER(val) IN ('true','1','y','yes') THEN 1 ELSE 0 END AS bitval; |
SELECT TRY_TO_BOOLEAN(val) AS b; |
SELECT SAFE_CAST(val AS BOOL) AS b; |
To String (format) | SELECT CONVERT(varchar(10), OrderDate, 23) AS iso_date; -- YYYY-MM-DD |
SELECT TO_VARCHAR(OrderDate, 'YYYY-MM-DD') AS iso_date; |
SELECT FORMAT_DATE('%F', OrderDate) AS iso_date; |
String → JSON | -- No JSON type. Keep NVARCHAR, use OPENJSON to shred: SELECT * FROM OPENJSON(@json); |
SELECT PARSE_JSON('{"a":1,"b":"x"}') AS j; -- VARIANT |
SELECT PARSE_JSON('{"a":1,"b":"x"}') AS j; -- JSON -- Safe variant: SELECT SAFE.PARSE_JSON(json_str) AS j; |
Any → JSON String | -- Build JSON via FOR JSON: SELECT * FROM T FOR JSON AUTO; |
SELECT TO_JSON(OBJECT_CONSTRUCT('a',1,'b','x')) AS json_s; |
SELECT TO_JSON(STRUCT(1 AS a, 'x' AS b)) AS json_s; |
Date/Time Families | -- date, datetime, datetime2, time, smalldatetime |
-- DATE, TIME, TIMESTAMP_NTZ/LTZ/TTZ |
-- DATE, DATETIME, TIME, TIMESTAMP |
Joining Tables
Join Type | SQL Server | Snowflake | BigQuery |
---|---|---|---|
INNER JOIN | SELECT c.CustomerName, o.OrderID FROM Customers c INNER JOIN Orders o ON c.CustomerID = o.CustomerID; |
SELECT c.CustomerName, o.OrderID FROM Customers c JOIN Orders o ON c.CustomerID = o.CustomerID; |
SELECT c.CustomerName, o.OrderID FROM `project.dataset.Customers` c JOIN `project.dataset.Orders` o ON c.CustomerID = o.CustomerID; |
LEFT JOIN | SELECT c.CustomerName, o.OrderID FROM Customers c LEFT JOIN Orders o ON c.CustomerID = o.CustomerID; |
SELECT c.CustomerName, o.OrderID FROM Customers c LEFT JOIN Orders o ON c.CustomerID = o.CustomerID; |
SELECT c.CustomerName, o.OrderID FROM `project.dataset.Customers` c LEFT JOIN `project.dataset.Orders` o ON c.CustomerID = o.CustomerID; |
RIGHT JOIN | SELECT c.CustomerName, o.OrderID FROM Customers c RIGHT JOIN Orders o ON c.CustomerID = o.CustomerID; |
SELECT c.CustomerName, o.OrderID FROM Customers c RIGHT JOIN Orders o ON c.CustomerID = o.CustomerID; |
SELECT c.CustomerName, o.OrderID FROM `project.dataset.Customers` c RIGHT JOIN `project.dataset.Orders` o ON c.CustomerID = o.CustomerID; |
FULL OUTER JOIN | SELECT c.CustomerName, o.OrderID FROM Customers c FULL OUTER JOIN Orders o ON c.CustomerID = o.CustomerID; |
SELECT c.CustomerName, o.OrderID FROM Customers c FULL OUTER JOIN Orders o ON c.CustomerID = o.CustomerID; |
SELECT c.CustomerName, o.OrderID FROM `project.dataset.Customers` c FULL OUTER JOIN `project.dataset.Orders` o ON c.CustomerID = o.CustomerID; |
CROSS JOIN | SELECT c.CustomerName, p.ProductName FROM Customers c CROSS JOIN Products p; |
SELECT c.CustomerName, p.ProductName FROM Customers c CROSS JOIN Products p; |
SELECT c.CustomerName, p.ProductName FROM `project.dataset.Customers` c CROSS JOIN `project.dataset.Products` p; |
SELF JOIN | SELECT e1.EmployeeName, e2.ManagerName FROM Employees e1 JOIN Employees e2 ON e1.ManagerID = e2.EmployeeID; |
SELECT e1.EmployeeName, e2.ManagerName FROM Employees e1 JOIN Employees e2 ON e1.ManagerID = e2.EmployeeID; |
SELECT e1.EmployeeName, e2.ManagerName FROM `project.dataset.Employees` e1 JOIN `project.dataset.Employees` e2 ON e1.ManagerID = e2.EmployeeID; |
Semi Join (Exists) | SELECT c.CustomerName FROM Customers c WHERE EXISTS ( SELECT 1 FROM Orders o WHERE o.CustomerID = c.CustomerID ); |
SELECT c.CustomerName FROM Customers c WHERE EXISTS ( SELECT 1 FROM Orders o WHERE o.CustomerID = c.CustomerID ); |
SELECT c.CustomerName FROM `project.dataset.Customers` c WHERE EXISTS ( SELECT 1 FROM `project.dataset.Orders` o WHERE o.CustomerID = c.CustomerID ); |
Anti Join (Not Exists) | SELECT c.CustomerName FROM Customers c WHERE NOT EXISTS ( SELECT 1 FROM Orders o WHERE o.CustomerID = c.CustomerID ); |
SELECT c.CustomerName FROM Customers c WHERE NOT EXISTS ( SELECT 1 FROM Orders o WHERE o.CustomerID = c.CustomerID ); |
SELECT c.CustomerName FROM `project.dataset.Customers` c WHERE NOT EXISTS ( SELECT 1 FROM `project.dataset.Orders` o WHERE o.CustomerID = c.CustomerID ); |
CTE
CTE Topic | SQL Server | Snowflake | BigQuery |
---|---|---|---|
Basic CTE | WITH TopSales AS ( SELECT CustomerID, Amount FROM Sales WHERE Amount > 1000 ) SELECT * FROM TopSales; |
WITH TopSales AS ( SELECT CustomerID, Amount FROM Sales WHERE Amount > 1000 ) SELECT * FROM TopSales; |
WITH TopSales AS ( SELECT CustomerID, Amount FROM `project.dataset.Sales` WHERE Amount > 1000 ) SELECT * FROM TopSales; |
Multiple CTEs | WITH f AS ( SELECT * FROM Sales WHERE Amount > 1000 ), g AS ( SELECT CustomerID, SUM(Amount) AS Total FROM f GROUP BY CustomerID ) SELECT * FROM g; |
WITH f AS ( SELECT * FROM Sales WHERE Amount > 1000 ), g AS ( SELECT CustomerID, SUM(Amount) AS Total FROM f GROUP BY CustomerID ) SELECT * FROM g; |
WITH f AS ( SELECT * FROM `project.dataset.Sales` WHERE Amount > 1000 ), g AS ( SELECT CustomerID, SUM(Amount) AS Total FROM f GROUP BY CustomerID ) SELECT * FROM g; |
CTE with INSERT | WITH agg AS ( SELECT CustomerID, SUM(Amount) AS Total FROM Sales GROUP BY CustomerID ) INSERT INTO CustTotals(CustomerID, Total) SELECT CustomerID, Total FROM agg; |
WITH agg AS ( SELECT CustomerID, SUM(Amount) AS Total FROM Sales GROUP BY CustomerID ) INSERT INTO CustTotals (CustomerID, Total) SELECT CustomerID, Total FROM agg; |
WITH agg AS ( SELECT CustomerID, SUM(Amount) AS Total FROM `project.dataset.Sales` GROUP BY CustomerID ) INSERT INTO `project.dataset.CustTotals` (CustomerID, Total) SELECT CustomerID, Total FROM agg; |
CTE with UPDATE/DELETE | -- UPDATE via CTE WITH d AS ( SELECT CustomerID, SUM(Amount) AS Total FROM Sales GROUP BY CustomerID ) UPDATE c SET c.Total = d.Total FROM CustTotals c JOIN d ON c.CustomerID = d.CustomerID; -- DELETE via CTE WITH old AS (SELECT * FROM Logs WHERE CreatedAt < '2025-01-01') DELETE FROM old; |
-- UPDATE via CTE WITH d AS ( SELECT CustomerID, SUM(Amount) AS Total FROM Sales GROUP BY CustomerID ) UPDATE CustTotals c SET Total = d.Total FROM d WHERE c.CustomerID = d.CustomerID; -- DELETE via CTE WITH old AS (SELECT * FROM Logs WHERE CreatedAt < '2025-01-01') DELETE FROM Logs USING old WHERE Logs.id = old.id; |
-- UPDATE via CTE WITH d AS ( SELECT CustomerID, SUM(Amount) AS Total FROM `project.dataset.Sales` GROUP BY CustomerID ) UPDATE `project.dataset.CustTotals` c SET Total = d.Total FROM d WHERE c.CustomerID = d.CustomerID; -- DELETE via CTE WITH old AS (SELECT id FROM `project.dataset.Logs` WHERE CreatedAt < DATE '2025-01-01') DELETE FROM `project.dataset.Logs` WHERE id IN (SELECT id FROM old); |
Recursive CTE (Hierarchy) | WITH EmpCTE AS ( SELECT EmployeeID, ManagerID, 0 AS lvl FROM Employees WHERE ManagerID IS NULL UNION ALL SELECT e.EmployeeID, e.ManagerID, c.lvl + 1 FROM Employees e JOIN EmpCTE c ON e.ManagerID = c.EmployeeID ) SELECT * FROM EmpCTE OPTION (MAXRECURSION 100); |
WITH RECURSIVE EmpCTE AS ( SELECT EmployeeID, ManagerID, 0 AS lvl FROM Employees WHERE ManagerID IS NULL UNION ALL SELECT e.EmployeeID, e.ManagerID, c.lvl + 1 FROM Employees e JOIN EmpCTE c ON e.ManagerID = c.EmployeeID ) SELECT * FROM EmpCTE; |
WITH RECURSIVE EmpCTE AS ( SELECT EmployeeID, ManagerID, 0 AS lvl FROM `project.dataset.Employees` WHERE ManagerID IS NULL UNION ALL SELECT e.EmployeeID, e.ManagerID, c.lvl + 1 FROM `project.dataset.Employees` e JOIN EmpCTE c ON e.ManagerID = c.EmployeeID ) SELECT * FROM EmpCTE; |
Recursive CTE (Date Series) | WITH Dates AS ( SELECT CAST('2025-01-01' AS date) AS d UNION ALL SELECT DATEADD(DAY, 1, d) FROM Dates WHERE d < '2025-01-31' ) SELECT * FROM Dates OPTION (MAXRECURSION 0); |
WITH RECURSIVE Dates AS ( SELECT TO_DATE('2025-01-01') AS d UNION ALL SELECT DATEADD(day, 1, d) FROM Dates WHERE d < TO_DATE('2025-01-31') ) SELECT * FROM Dates; |
WITH RECURSIVE Dates AS ( SELECT DATE '2025-01-01' AS d UNION ALL SELECT DATE_ADD(d, INTERVAL 1 DAY) FROM Dates WHERE d < DATE '2025-01-31' ) SELECT * FROM Dates; |
CTE vs Materialization | -- CTE is not materialized. -- Use #temp or @table for reuse: SELECT ... INTO #t FROM ...; -- or: WITH c AS (...) SELECT ... FROM c; |
-- CTE not materialized. -- Use TEMP TABLE or transient table: CREATE TEMP TABLE t AS SELECT ...; WITH c AS (...) SELECT ... FROM c; |
-- CTE not materialized by default. -- BigQuery supports MATERIALIZED CTE hint: WITH c AS MATERIALIZED (SELECT ... ) SELECT ... FROM c; |
Notes & Scope | -- Scope: single statement. -- Name must be unique within WITH. -- Recursive needs OPTION(MAXRECURSION ...). |
-- Scope: single statement. -- Use WITH RECURSIVE for recursion. -- Can precede DML/DDL that supports SELECT. |
-- Scope: single statement. -- WITH RECURSIVE supported. -- MATERIALIZED can improve reuse/perf. |