Querying temporal table with date/time fields - sql-server

I need to write a query to get following output using temporal table feature in SQL server 2016.
Customer Table (system versioned table)
Id
Name
[period_start] [datetime2](7) GENERATED ALWAYS AS ROW START NOT NULL
[period_end] [datetime2](7) GENERATED ALWAYS AS ROW END NOT NULL
Orders Table
Id
CustomerId
..
[creation_date] DATETIME default SYSUTCDATETIME()
Output : OrderId, ... , Customer Name
Customer name should be the reflect the correct name which relevant to the order date
Following query will give me the required output but I need to check whether this is the correct way of doing this type of queries..
SELECT T.Id, O.Name
FROM Orders T
INNER JOIN (
SELECT *
FROM Customer
FOR SYSTEM_TIME FROM '1900-01-01' TO '9999-12-31 23:59:59.9999999'
) O ON T.CustomerId = O.ID
AND T.creation_date BETWEEN O.period_start AND O.period_end
Thanks in advance
Chaminda.

I see nothing wrong with it, except perhaps the nested query is unnecessary:
SELECT T.Id, O.Name
FROM Orders T
JOIN Customer FOR SYSTEM_TIME FROM '1900-01-01' TO '9999-12-31 23:59:59.9999999' O
ON T.CustomerId = O.ID
WHERE T.creation_date BETWEEN O.period_start AND O.period_end

You seem to have extraneous criteria in your query. I think this does everything you've asked for:
SELECT T.Id, O.Name
FROM Orders T INNER JOIN Customer O
ON T.CustomerId = O.ID

Related

Check constraints not working on a query/view with join

We have a view described as the following :
CREATE view [dbo].[PriceHourlyView]
AS
select NodeId, TimeStamp,RtDa,MarketId,Lmp,Mlc,Mcc,Issettledprice,datecreated,IsCalculated from dbo.PriceHourly WITH (NOLOCK)
union all
select NodeId, TimeStamp,RtDa,MarketId,Lmp,Mlc,Mcc,Issettledprice,datecreated,IsCalculated from dbo.PriceHourly2018 WITH (NOLOCK)
union all
select NodeId, TimeStamp,RtDa,MarketId,Lmp,Mlc,Mcc,Issettledprice,datecreated,IsCalculated from dbo.PriceHourly2017 WITH (NOLOCK)
union all
select NodeId, TimeStamp,RtDa,MarketId,Lmp,Mlc,Mcc,Issettledprice,datecreated,IsCalculated from dbo.PriceHourly2016 WITH (NOLOCK)
union all
select NodeId, TimeStamp,RtDa,MarketId,Lmp,Mlc,Mcc,Issettledprice,datecreated,IsCalculated from dbo.PriceHourly2015 WITH (NOLOCK)
union all
select NodeId, TimeStamp,RtDa,MarketId,Lmp,Mlc,Mcc,Issettledprice,datecreated,IsCalculated from dbo.PriceHourly2014 WITH (NOLOCK)
union all
select NodeId, TimeStamp,RtDa,MarketId,Lmp,Mlc,Mcc,Issettledprice,datecreated,IsCalculated from dbo.PriceHourly2013 WITH (NOLOCK)
union all
select NodeId, TimeStamp,RtDa,MarketId,Lmp,Mlc,Mcc,Issettledprice,datecreated,IsCalculated from dbo.PriceHourly2012 WITH (NOLOCK)
Each of the tables has a check constraint as follows for each year except for the current table without year specified :
ALTER TABLE [dbo].[PriceHourly2017] WITH CHECK ADD CONSTRAINT [CK_PriceHourly2017_Timestamp] CHECK (([timestamp]>='2017-01-01' AND [timestamp]<='2017-12-31 23:59'))
When this view is queried by itself the check constraints limit the tables being searched. The execution plan looks like this :
SELECT
*
FROM PriceHourlyview
WHERE nodeid = 24511
AND TimeStamp BETWEEN '2017-05-17' AND '2017-05-24'
Now when I join on this table on the timestamp field the query no longer uses the check constraints and uses every table to check for the data.
SELECT
*
FROM ShapeProfileDetails s WITH (NOLOCK)
LEFT JOIN PriceHourlyView p WITH (NOLOCK)
ON s.TimeStamp = p.Timestamp
AND s.EffectiveDate BETWEEN '2017-05-17' AND '2017-05-24'
WHERE NodeId = 24512
--AND s.EffectiveDate BETWEEN '2017-05-17' AND '2017-05-24'
I know I'm not querying the same field in the joined example and assuming that's the issue but that is the field I need to query for the correct results. I'm wondering if there is anyway to hint or force the query to use the correct check constraints. Or what is the best practice on joining to try and utilize these check constraints.
Okay, as discussed we know that EffectiveDate and TimeStamp are nearly the same. I would try to do something like this. Technically it's the same query, but we will let know SQL Server that it can use constraints (just subtract and add one day on the edges of BETWEEN).
SELECT * FROM ShapeProfileDetails s WITH (NOLOCK)
JOIN PriceHourlyView p WITH (NOLOCK)
ON s.TimeStamp = p.Timestamp
AND s.EffectiveDate BETWEEN '2017-05-17' AND '2017-05-24'
AND s.TimeStamp BETWEEN '2017-05-16' AND '2017-05-25'
WHERE NodeId = 24512

How to do sub-query correctly while selecting two tables in Oracle?

I need to do a sub-query from a table to find all employees working in the same department that is part of the same city, but I'm not getting it.
I have the following tables:
Table departments
DEPARTMENTS
department_id
department_name
location_id
Table locations
LOCATIONS
location_id
street_address
postal_code
city
state_province
country_id
Table employees
EMPLOYEES
employee_id
first_name
last_name
email
phone_number
hire_date
job_id
department_id
My code right now is something like that :
SELECT
firt_name,
department_id,
job_id
FROM employees
WHERE state_province = (SELECT state_province FROM locations
WHERE state_province = 'Sao Paulo');
The problem is that while I want to select state_province from the table locations, I can't select the name, department id and job id from the table employees. How can I select both tables while doing the sub-query ?
Anyway, sorry if I did something wrong in the code, I am new to sub-queries.
You could try doing a join between the two tables instead:
SELECT
e.firt_name,
e.department_id,
e.job_id,
l.* -- replace with columns you really want
FROM employees e
INNER JOIN locations l
ON e.state_province = l.state_province
WHERE
e.state_province = 'Sao Paulo';
I don't know which columns you want to select from locations, but it doesn't really make sense to do a join just for state_province alone, as the employees table already has this column. So I just included location.* as a placeholder which you can replace with the columns you actually want.
Edit:
A join is the way to go here IMO, but if you absolutely need to use a subquery, then you can move your current subquery from the WHERE clause to the SELECT clause:
SELECT
firt_name,
department_id,
job_id,
(SELECT l.state_province FROM locations l
WHERE e.state_province = l.state_province) state_province
FROM employees e;
Note that this will only work if there is one matching province. For this and performance reasons, my join query is probably what you would want to use in practice.
I think in your case, sub-query may not be necessary.
A join table can do the trick.
SELECT e.first_name, e.department_id, e.job_id, l.state_province
FROM employees e
LEFT JOIN departments d ON e.department_id = d.department_id
LEFT JOIN locations l ON d.location_id = l.location_id
WHERE l.state_province = 'Sao Paulo';

Having issues returning 4 columns by joining 3 tables and using aliases in SQL?

I am still very new at SQL and was unable to find an answer on here...I am supposed to write a SELECT statement that returns 4 columns from 3 tables using aliases and then assign correlation names to the tables... But I am getting an error on the WHERE clause and I am not quite sure how to join the 3 tables to get the results I am looking for. Also, it did not specify which type of JOIN to do.
Here is my code:
SELECT VendorName AS [Vendor], InvoiceDate AS [Date], InvoiceNumber AS [Number], AccountItemDescription AS [Description]
FROM Vendors AS v JOIN Invoices AS i
ON v.VendorID = i.InvoiceID
JOIN InvoiceLineItems AS l JOIN GLAccounts AS g
WHERE l.InvoiceLineItems = g.GLAccounts
ORDER BY Vendor, Description;-- Unfinished
Getting this error:
Msg 156, Level 15, State 1, Line 6
Incorrect syntax near the keyword 'WHERE'.
Any tips would be GREATLY appreciated...
It helps to be careful in how you format your code. Every join should have an on clause. You are missing them on your InvoiceLineItems and GLAccounts joins.
Additionally, your on clause will typically link the primary key of one table to the foreign key in another; joining Vendors to Invoices by equating vendorID to invoiceID is not going to give you accurate results. Those IDs have no direct correlation. You want to link vendorID from one table to the vendorID in the other. I'm not sure how your fields are named; it could be i.vendorID = v.vendorID or it could be something like i.vendorID = v.id. Follow the same pattern for your other joins.
You'll end up with something like this:
SELECT VendorName AS [Vendor],
InvoiceDate AS [Date],
InvoiceNumber AS [Number],
AccountItemDescription AS [Description]
FROM Vendors AS v
JOIN Invoices AS i ON i.VendorID = v.VendorID
JOIN InvoiceLineItems AS l ON l.InvoiceID = i.InvoiceID
JOIN GLAccounts AS g ON l.GLAccountID = g.GLAccountID
ORDER BY Vendor, Description;
Change it to:
SELECT VendorName AS [Vendor], InvoiceDate AS [Date],
InvoiceNumber AS [Number], AccountItemDescription AS [Description]
FROM Vendors AS v
JOIN Invoices AS i ON v.VendorID = i.InvoiceID
JOIN InvoiceLineItems AS l --YOU MISS AN ON CLAUSE HERE
JOIN GLAccounts AS g ON l.InvoiceLineItems = g.GLAccounts
ORDER BY Vendor, Description;
You add the joining in an old style leaving the new one without the ON clause which was generating the error
Since I don't know your table structure I can't suggest what to put there.

How to optimize view performance in SQL Server 2012 by indexing

I have a view like that:
create view dbo.VEmployeeSalesOrders
as
select
employees.employeeID, Products.productID,
Sum(Price * Quantity) as Total,
salesDate,
COUNT_BIG() as [RecordCount]
from
dbo.Employees
inner join
dbo.sales on employees.employeeID = sales.employeeID
inner join
dbo.products on sales.productID = products.ProductID
group by
Employees.employeeID, products.ProductID, salesDate
When I select * from dbo.VEmployeeSalesOrders it takes 97% of the execution plan. It needs it to be faster.
And when I try to create an index, an exception fires with the following message:
select list doesn't include a proper use on count_Big()
Why am getting this error?
1-first you need to alter your view and make it contains COUNT_BIG() function because you used aggregate function in select statment,
AND THE REASON FOR USING THAT is that SQL Server needs to track the record where the record is ,number of records
like this
create view dbo.VEmployeeSalesOrders
as
select employees.employeeID,Products.productID,Sum(Price*Quantity)
as Total,salesDate,COUNT_BIG(*) as [RecordCount]
from dbo.Employees
inner join dbo.sales on employees.employeeID=sales.employeeID
inner join dbo.products on sales.productID-products.ProductID
group by Employees.employeeID,products.ProductID,salesDate
2- then you need to create index like that
Create Unique Clustered Index Cidx_IndexName
on dbo.VEmployeeSalesOrders(employedID,ProductID,SalesDate)
Hope It Works

Need help creating a query for a non-normalized database

I've never worked with a non-normalized database before, so I'll try and explain my problem as best I can. So I have two tables:
The customers table holds all the customers information, and the orders table holds all the orders that they have placed. I haven't listed all the fields in the tables, just the ones that I need. The customer number in both tables is not the primary key, but I'm inner joining on them anyway. So the problem I'm having is that I don't know how to make a query that:
Selects all the customers with their first name, last name, and email, and also show the most recent orderdate, most recent total, and most recent ordertype. I know that I have to use a max() aggregate for the date, but that's as far as I got. Please help a noob out.
You can try:
SELECT FirstName,
LastName,
Email,
OrderDate,
OrderTotal,
OrderType
FROM Customers AS C
INNER JOIN Order AS O
ON O.CustomerNumber = C.CustomerNumber AND
O.OrderDate = (
SELECT MAX (O1.OrderDate)
FROM Order AS O1
WHERE O1.CustomerNumber = C.CustomerNumber)
)
assuming that Orders.OrderDate is unique for each CustomerNumber, does this work for you? if a single CustomerNumber has more than one entry in Order for OrderDate, you'll get each of those rows.
select c.FirstName, c.LastName, c.Email, o.OrderDate, o.OrderTotal, o.OrderType
from Customers c
join
(select CusomterNumber, max(OrderDate) as MostRecentOrderDate
from Orders
group by CustomerNumber
) mro on mro.CustomerNumber=s.CustomerNumber
join Orders o on o.OrderDate=mro.MostRecentOrdeDate and
o.CustomerNumber=mro.CustomerNumber
Try this:
SELECT
Customers.*, Orders.*
FROM
Customers
JOIN
(SELECT
Customer_Number,
MAX(Order_Date) OrderDate
FROM
Orders
GROUP BY
Customer_Number
) as Ord ON Customers.Customer_Number = Ord.Customer_Number
JOIN Order ON Orders.Customer_Number = Ord.Customer_Number
If you are doing this with SQL Server use the query designer and basically all you want to do is do a join since you have two keys that are the same one in Customer Table ->Customer Join on Order->Customer alias the Customer table as C and Orders table as O
so for example
SELECT Customer.*, Orders.*
From Customer c, Orders O INNER JOIN O where C.Customer Number = O.Customer Number
This should be enough to get you started.. if you don't want all the fields then fully qualify the names for example
SELECT C.FirstName, C.LastName, O.OrderDate, O.OrderType FROM Customer C, Orders O
WHERE C.Customer NUmber = O.Customer Number //this is another way of doing a Join when working with the where Clause.

Resources