Unique constraint based on weeks in a quarter - sql-server

I am trying to figure out how to apply a unique constraint based on weeks in a quarter.
I have a table that includes Quarter (1Q2014, 2Q2014, ...) as well as an Effective Date and an Expiration date.
I need to allow multiple records for the same Qtr as long as Effective and Expiration Dates do not overlap.
For example, these records would be legitimate:
Qtr EffDte ExpDte
--------------------------------------
1Q2014 2014-01-06 2014-02-03
1Q2014 2014-02-10 2014-02-24
1Q2014 2014-03-03 2014-03-17
While these records would not be legitimate:
Qtr EffDte ExpDte
--------------------------------------
1Q2014 2014-01-06 2014-03-24
1Q2014 2014-02-10 2014-03-10
1Q2014 2014-03-03 2014-03-17
I am not sure if I need to alter my table design to achieve this goal.
Does anyone have any suggestions?

Related

Created date dimension unable to slicing through cube

My RDBMS is SQL Sserver, and I'm working on SSAS.
Fact: I have a fact called fact
date | payment
2014-01-04 00:00:00 |198000.00
2015-01-02 00:00:00 |381400.00
2017-01-01 00:00:00 |70500.00
2019-01-03 00:00:00 |891000.00
2015-02-02 00:00:00 |22000.00
...
and then I created time dimension on SSAS by creating time dim
- Generating table in data source
- I choose 5 time periods = year, halfyear, quarter, month, date
- I choose regular calendar
It creates this much column
[PK_Date]
,[Date_Name]
,[Year]
,[Year_Name]
,[Half_Year]
,[Half_Year_Name]
,[Quarter]
,[Quarter_Name]
,[Month]
,[Month_Name]
,[Day_Of_Year]
,[Day_Of_Year_Name]
,[Day_Of_Half_Year]
,[Day_Of_Half_Year_Name]
,[Day_Of_Quarter]
,[Day_Of_Quarter_Name]
,[Day_Of_Month]
,[Day_Of_Month_Name]
,[Month_Of_Year]
,[Month_Of_Year_Name]
,[Month_Of_Half_Year]
,[Month_Of_Half_Year_Name]
,[Month_Of_Quarter]
,[Month_Of_Quarter_Name]
,[Quarter_Of_Year]
,[Quarter_Of_Year_Name]
,[Quarter_Of_Half_Year]
,[Quarter_Of_Half_Year_Name]
,[Half_Year_Of_Year]
,[Half_Year_Of_Year_Name]
,[Fiscal_Year]
,[Fiscal_Year_Name]
,[Fiscal_Half_Year]
,[Fiscal_Half_Year_Name]
,[Fiscal_Quarter]
,[Fiscal_Quarter_Name]
,[Fiscal_Month]
,[Fiscal_Month_Name]
,[Fiscal_Day]
,[Fiscal_Day_Name]
,[Fiscal_Day_Of_Year]
,[Fiscal_Day_Of_Year_Name]
,[Fiscal_Day_Of_Half_Year]
,[Fiscal_Day_Of_Half_Year_Name]
,[Fiscal_Day_Of_Quarter]
,[Fiscal_Day_Of_Quarter_Name]
,[Fiscal_Day_Of_Month]
,[Fiscal_Day_Of_Month_Name]
,[Fiscal_Month_Of_Year]
,[Fiscal_Month_Of_Year_Name]
,[Fiscal_Month_Of_Half_Year]
,[Fiscal_Month_Of_Half_Year_Name]
,[Fiscal_Month_Of_Quarter]
,[Fiscal_Month_Of_Quarter_Name]
,[Fiscal_Quarter_Of_Year]
,[Fiscal_Quarter_Of_Year_Name]
,[Fiscal_Quarter_Of_Half_Year]
,[Fiscal_Quarter_Of_Half_Year_Name]
,[Fiscal_Half_Year_Of_Year]
,[Fiscal_Half_Year_Of_Year_Name]
After the dimension created I link it to the fact.
They are successfully built. After I browse the cube this comes out.
month |payment
2014-01-04 00:00:00 |40982534943.62
2015-01-02 00:00:00 |40982534943.62
2017-01-01 00:00:00 |40982534943.62
2019-01-03 00:00:00 |40982534943.62
2015-02-02 00:00:00 |40982534943.62
....
Which possibly not the result I need
Why is this happening? I have change the datatype of time dimension to be the same as the date type in fact.
i solve it by change the pk column name from time dimension same as fact date column. After i reload the project and remake it the relationship automatically made. when the fk column name was different as the fact column i make it manually.
solution :
make the column name the same. whether you change the dimension column into fact or change fact column into dimension.

How to convert a date column in TSQL to display only the month and year

I have a column called DateId that is an int, and displays the date as 20190626. I was able to convert it to a date using the below query, but I would like to display it only as Month and Year.
I have three columns DateId, Customer and PayAmount, all from the same table. There are Many customers who have multiple payments each month and I would like to group by each month combining all the payments each month per customer.
Select
Convert(Date, Convert(Char(8), DateId), 112) As [Date],
Sum(PayAmount), Customer
from
Pay
Group By
Customer, DateId
What I get:
DateId PayAmount Customer
--------------------------------------
2019-06-20 $100 A
2019-06-24 $200 B
2019-04-22 $100 B
2019-03-20 $300 A
2019-04-22 $100 B
2019-06-21 $200 A
2019-06-21 $100 B
What I want:
DateId PayAmount Customer
-------------------------------------
2019-06 $300 A
2019-06 $300 B
2019-04 $200 B
2019-03 $300 A
Another option is to use the implicit conversion. In this case, LEFT(DateID,7).
Example Updated for INT
Select DateID = stuff(left(DateID,6),5,0,'-')
,[PayAmount] = sum([PayAmount])
,Customer
From YourTable
Group By left(DateID,6),Customer
Returns
DateID PayAmount Customer
2019-03 300 A
2019-06 300 A
2019-04 200 B
2019-06 300 B
This seems like you just need the first 7 characters of the ISO8601 style:
CONVERT(varchar(7),DateId,126)
If you want to retain the date datatype, then you'll need to "round" the date to the start of the month. One common way of doing this is the below method of getting the difference in months between the value and date "0" (1900-01-01):
CONVERT(date,DATEADD(MONTH,DATEDIFF(MONTH, 0, DateId),0))
If you then need to show the format yyyy-MM you can set that as your format in your presentation layer.
If you need to group by that as well, then add that expression to your GROUP BY clause.

Calculate the rolling time since an event for each record in SQL

I am working on a query to calculate the time since the latest preventative maintenance (PM) for each piece of equipment on a rolling calendar. The goal is build a dataframe to analyze when a repair will take place.
Below is a table of the query results that I have with the added column "Time Since Last PM" which is the column that I want.
Call this Table 1:
EquipmentNumber |Year |weeknumber |Current Week Repair|Time Since Last PM
2069186 |2018 |10 |1 |5
2069186 |2018 |21 |1 |1
1626930 |2018 |09 |1 |21
1626930 |2019 |03 |1 |15
The preventative maintenance data comes from a query/table that is set up like the following i.e. Table 2.
Equipment Number |Year |WeekNumber
2069186 |2018 |5
2069186 |2018 |20
1626930 |2017 |40
1626930 |2018 |40
So I need to make sure that for my final query, Table 1, the “Time Since Last PM” for equipment 2069186 the first record is difference from week 5 2018 in Table 2 to week 10 2018. For the second record of equipment 2069186 the “Time Since Last PM” should be the difference between week 21 2018 in Table 1 and week 20 2018 in Table 2. For equipment 1626930 the first record should be the difference from week 9 2018 in Table 1 to week 40 2017 in Table 2. For equipment 1626930 the second record should be the difference from week 3 2019 in Table 1 to week 40 2018 in Table 2. Keep in mind that I want the difference between the current record in Table 1 and the latest PM prior to the year and week in Table 1.
The queries for Table 1 and Table 2 are very basic.
SELECT
DISTINCT EquipmentNumber,
Year,
weeknumber,
[Current Week Repair]
FROM TableA
SELECT
EquipmentNumber,
DatePart(Year, Created) as Year,
DatePart(Week, Created) as WeekNumber
FROM TableB
Any suggestions on the proper way to join the two tables and make the calculation? Or is there a way to utilize temp tables and variables that anyone can suggest? Any input would be appreciated!
You can use APPLY:
SELECT t1.*, t1.WeekNumber - ca.WeekNumber
FROM t1
OUTER APPLY (
SELECT TOP 1 Year, WeekNumber
FROM t2
WHERE Equipment_Number = t1.Equipment_Number
AND (
(Year < t1.Year)
OR
(Year = t1.Year AND WeekNumber < t1.WeekNumber)
)
ORDER BY Year DESC, WeekNumber DESC
) AS ca
Calculating week number difference will be tricky and for that you'll need the number of weeks in the previous year.

Calculate payments on a month by month bases from date opened SQL 2008

I'm currently trying to replicate an old report that used to produce a rolling sum of collections. However it wasn't a standard month on month. Here is screen shot of the excel based report.
The blue section is based on a simple query and gives the dataset used to start(EXAMPLE):
SELECT COUNT(AccountNo) AS Number, SUM(Balance) AS Value, DATENAME(MM,DateOpened) AS Month, DATEPART(Y,DateOpened) AS Year FROM tblAccounts
GROUP BY DATENAME(MM,DateOpened), DATEPART(Y,DateOpened)
The tables are very basic :
AccountNo | Balance | DateOpened
12345 | 1245.55 | 01/01/2015
I'm struggling to get it to work out the months on a rolling basis, so Month 1 for Apr 2011 will be the first month for those files (payments in April), month 2 would be payments in May for the accounts opened in April (I hope that is clear).
So this means Month 1 for April would be April, and Month 1 for Nov would be Nov. Payments are stored in a table tblPayments
AccountNo | DatePayment | PaymentValue
12345 | 02/02/2015 | 15.99
Please ask if I haven't been clear enough
Assuming you have a column called "DatePayment", you should simply do something like this:
SELECT COUNT(AccountNo) AS Number, SUM(Balance) AS Value,
DATENAME(MM,DateOpened) AS Month, DATEPART(Y,DateOpened) AS Year,
DATEDIFF(MONTH, DateOpened, DatePayment) AS MonthN
FROM [...]
GROUP BY DATENAME(MM,DateOpened), DATEPART(Y,DateOpened),
DATEDIFF(MONTH, DateOpened, DatePayment)
The DATEDIFF simply counts the months between the date the account was opened and the date of the payment. Note that you might want to change the DateOpened to always be the 1st of the month in the DATEDIFF calculation.
In the FROM [...] part of your query, you will need a join between your Payments-table and the table holding your accounts, in order to be able to compare DateOpened with DatePayment. You should join them on the AccountNo-column. This looks something like this:
FROM Accounts INNER JOIN Payments ON Accounts.AccountNo = Payments.AccountNo
After doing this, you will need to make sure that all references to columns that exist in both tables are fully qualified. This means that COUNT(AccountNo) should be changed to COUNT(Accounts.AccountNo), etc.

Repeate Parent column in child table

I have following Three tables
Periods
--------------------------------
ID StartDate EndDate Type
--------------------------------
1 2013-01-01 2013-01-01 D
2 2013-01-02 2013-01-02 D
Attendance
---------------------------------------------------
ID PeriodID UploadedBy uploadDateTime Approved
--------------------------------------------------
1 1 25 2013-01-01-11:00 1
2 1 54 2013-01-01-10:00 1
Attendance Detail
---------------------------------------------
ID EmployeeID AttendanceTime Status AttendanceID
---------------------------------------------
1 24 2013-01-01 09:05 CheckIn 1
1 28 2013-01-01 09:08 CheckOut 2
Attendance data is filled through biomatric machined generated CSV files. Attendancedetail may group over time as there are multiple checkin out per employee per day. Attendance is approved for each period period.
Qustion
I need attendance data per period basis. I know I can achieve this though joins. but i have to use between filter on AttendenceTime. I was thinking to add PeriodID in AttendenceDetail table also to simplify queries and future performance issue. should I go for it or there is better solution available
If you often need Attendance details based per Period, so you usually need to join the three tables but the Attendance data (from the Attendance table) are not so important for you then the PeriodID in the Attendance Detail table will help you for sure.
Even if you need all three tables, a where condition on PeriodID will narrow down the number of rows from Attendance Detail, so it will be again helpful in terms of performance.
Maybe it can be a bit annoying to maintain a not fully normalized schema, but if it's not a big hassle and this doesn't impact your writing performance go for the PeriodID in the Attendance Detail. Your selects will thank you :)

Resources