how to format a table content - sql

I am new in database.I have execute a query like
SELECT name as request_name,
count(name) as no_of_open_req,
DATENAME(MM, Convert(DATE, created_date)) as month
FROM usm_request
WHERE DATENAME(YEAR, Convert(DATE,created_date)) = DATENAME(YEAR,GETDATE())
GROUP BY name,
DATENAME(YEAR, Convert(DATE, created_date)),
DATENAME(MM, Convert(DATE,created_date))
ORDER BY DATENAME(MM, Convert(DATE, created_date))
and got the result
request_name no_of_open_req month
Computer Request 1 April
Desk Phone Request 1 April
E-mail ID Creation Request 1 April
Computer Request 19 February
Desk Phone Request 12 February
Email ID Creation Request 8 February
Computer Request 45 January
Desk Phone Request 28 January
Email ID Creation Request 55 January
Computer Request 18 March
Desk Phone Request 24 March
E-mail ID Creation Request 35 March
But we need the result like
request_name January February March April
Computer Request 45 19 18 1
Desk Phone Request 28 12 24 1
E-mail ID Creation Request 55 8 35 1
Please help.
We have tried this query..
SELECT * from (select name as [request_name],
count(name) as [no_of_open_req],
DATENAME(MM, Convert(DATE, created_date)) as [month] FROM usm_request WHERE DATENAME(YEAR,Convert(DATE,created_date))=DATENAME(YEAR,GETDATE()) group by name, DATENAME(YEAR, Convert(DATE, created_date)),DATENAME(MM, Convert(DATE,created_date)))as t PIVOT(sum(no_of_open_req) FOR month IN (['January'],['February'],['March'],['April'])) AS PivotTable
and we are getting this as a result. ALL NULL VALUES
request_name 'January' 'February' 'March' 'April'
Cell Phone Allocation NULL NULL NULL NULL
Computer Request NULL NULL NULL NULL
Desk Phone Request NULL NULL NULL NULL
Desk Phone Request test NULL NULL NULL NULL
Email ID Creation Request NULL NULL NULL NULL
E-mail ID Creation Request NULL NULL NULL NULL
International Dialing Request NULL NULL NULL NULL
New Employee Request NULL NULL NULL NULL
New Non-Employee Request NULL NULL NULL NULL
Onboard a Non-Employee NULL NULL NULL NULL
Onboard a Non-Employee – Step 1 NULL NULL NULL NULL
Onboard a Non-Employee - Step 2 NULL NULL NULL NULL
Thanks
Monika

I think the problem is in the following part of your PIVOT statement:
FOR month IN (['January'],['February'],['March'],['April'])
Instead it should be
FOR month IN ([January],[February],[March],[April])
So, without the single-quotes. If you add those single quotes between the rectangular brackets, the statement will actually be looking for month values including the single quotes. For example, if you have ['January'] in your PIVOT list the statement will look for Month values of 'January'. Of course the values in the Month column do not have single-quotes in them.

Related

Transforming a dataset containing bank transactions into SQL Server

I would like to transform a dataset containing some bank transactions.
The ultimate goal is to make a report in Power BI to track daily expenses.
For this, I have the following situation that gives me a headache. :)
This is an example:
Date
Transaction_Details
Debit
Credit
21 Jan 2023
Transfer HomeBank
500
NULL
NULL
Reference: 4944
NULL
NULL
NULL
Beneficiary: David John
NULL
NULL
NULL
In Bank Account: RO97INGB1111333380218
500
NULL
20 Jan 2023
POS Payment
36
NULL
NULL
Card number: xxxx xxxx xxxx 1020
NULL
NULL
NULL
Terminal: OZKARDES A/S
NULL
NULL
NULL
Date: 19-01-2023
NULL
NULL
The desired output would be to transpose all rows in Transaction_Details that have NULL values in Date column, into a new column (e.g Other_Details) and for each transaction to add another column with "Transaction_Key".
Below, I have attached an example:
Transaction_Key
Date
Transaction_Details
Other_Details
Debit
Credit
1
21 Jan 2023
Transfer HomeBank
Reference: 4944, Beneficiary: David John, In Bank Account: RO97INGB1111333380218
500
NULL
2
20 Jan 2023
POS Payment
Card number: xxxx xxxx xxxx 1020, Terminal: OZKARDES A/S, Date: 19-01-2023
36
NULL
I used some COALESCE functions but it didn't work.
If we can assume you are able to create an Id/Sequence either in the data source or when importing the data, such that you end up with an incrementing number per row, then by using a windowed aggregation as follows you can convert your data as required:
select Transaction_Key,
Max(Date) Date,
Max(case when date is not null then Transaction_Details end) Transaction_Details,
String_Agg(case when date is null then Transaction_Details end, ',') Other_details,
Max(case when date is not null then Debit end) Debit,
Max(case when date is not null then Credit end) Credit
from (
select *,
Sum(case when date is null then 0 else 1 end) over(order by id) as Transaction_Key
from t
)t
group by Transaction_Key;
See this example Fiddle

Running SQL function in HUE IMPALA

I have started working on HUE IMPALA and I am stuck at a complex problem which I am not able to get through. So my table looks like this.
Id
Month
Base Rate
Payment
New Payment
a
Jan
1
100
NULL
a
Feb
1
100
NULL
a
Mar
1
100
NULL
a
Apr
2
NULL
NULL
a
May
3
NULL
NULL
a
Jun
4
NULL
NULL
a
Jul
5
NULL
NULL
So my aim is to fill the values in new payment column with this logic.
if Payment IS NULL THEN New Payment = (New Base Rate (current base rate - previous base rate)* Previous Payment) + Previous Payment... ELSE Payment
Eg: For mar new payment = 100
But for Apr, New Payment = 100 + (100* (1-1)) = 100
For this I have written the following code:
Select id, month,
CASE WHEN payment is NULL then
LAG(payment)
over(Partition BY id order by month) +
((LAG(payment)
over(Partition BY id order by month))*
(base_rate-lag(base_rate)
OVER (Partition by id order by month)))
Else payment end as New Payment
With this I get following answer
Id
Month
Base Rate
Payment
New Payment
a
Jan
1
100
100
a
Feb
1
100
100
a
Mar
1
100
100
a
Apr
2
NULL
100
a
May
3
NULL
NULL
a
Jun
4
NULL
NULL
a
Jul
5
NULL
NULL
Now the problem is the New Payment variable stops at May Month because there is NULL value in the Previous month (Apr) in the payment column. What I want is once the NULL value comes in the payment column, the code then starts using the updated value in new payment column in the above mentioned logic. So the answer I want is this:
Id
Month
Base Rate
Payment
New Payment
a
Jan
1
100
100
a
Feb
1
100
100
a
Mar
1
100
100
a
Apr
2
NULL
100
a
May
3
NULL
200
a
Jun
4
NULL
400
a
Jul
5
NULL
800
May -- New Payment = 100 + (100*(2-1)) = 200
June -- New Payment = 200 + (200 * (3-2))= 400
It's okay if a new variable needs to be created or if I have to split this code into multiple parts like create a table first then apply the rest of the logic. Entirely new logic which doesn't use the lag function is also welcome.

Select users based on their date joined and date left

I have the following table:
Person
UserID Name Date_Joined Date_Left
1 Test 2018-08-10 NULL
2 Test2 2018-07-10 NULL
3 Test3 2018-07-10 2018-12-31
4 Test4 2018-08-10 2018-09-10
I want to check by only their join and/or left date if they are billable(=active) or not.
These are billable users:
User whose start month is at least one month before billdate
with no date left
User whose start month is at least one month before billdate
with date left month equal to the billdate or later than the
billdate
Month of billing = always the previous month.
I use the following query:
DECLARE #billdate AS DATE = '2018-09-01';
SELECT *
FROM person
WHERE CompanyID = 1205 AND (
(
date_joined <= EOMONTH(#billdate, -1)
)
OR
(
date_left > EOMONTH(#billdate, -1) AND
date_left <= EOMONTH(#billdate)
)
)
My problems:
User Test4 is still present in my table if I set the billdate to 2018-11-01.
User Test3 dissapears if i set billdate to 2019-01-01
What is wrong with my query and how can I optimize this?
Sample data:
User list:
1 - Test - 2018-08-10 - NULL
2 - Test2 - 2018-07-10 - NULL
3 - Test3 - 2018-07-10 - 2018-12-31
4 - Test4 - 2018-08-10 - 2018-09-10
For the bill period of the previous month (= 8 / August) = #billdate 2018-09-10, these are the billable users:
Test2
Test3
However, when I change the bill period to 10 / october, these are the billable users:
Test
Test2
Test3
If I understand your logic correctly, a billable user is one whose start month is at least one month before the current month, and whose end month is less than or equal to the current month.
SELECT *,
CASE WHEN #billdate >= DATEADD(d, 1, EOMONTH(date_joined)) AND
(#billdate <= DATEADD(d, 1, EOMONTH(date_left)) OR date_left IS NULL)
THEN 'billable'
ELSE 'not billable' END AS status
FROM person;
This billing logic appears to be consistent with customers getting the first month free, but being billable from the second up to the final month.
Demo
use make flag comparing join month and year with bill month and year and create a flag for each user then use sub-query for filter
select * from t
(
select *,case when (month(date_joined)=month(billdate)
and year(date_joined)=year(billdate)) then 'N' else 'Y' end as flag_billable
from user
) as t where t.flag_billable='Y'
For your query
DECLARE #billdate AS DATE = '2018-09-01';
select * from
(
SELECT * ,case when (month(date_joined)=month(#billdate)
and year(date_joined)=year(#billdate)) then 'N' else 'Y' end as flag_billable
FROM person
) t where t.flag_billable='Y'

Dynamic 12 month rolling total for each previous month, going back 12 months

I have the following sql Code (where clause just to limit rows currently)
select
month,
monthname,
year,
count(distinct case when a.dim_service_type_id_desc like '%Direct Payment%' then a.DIM_PERSON_ID else null end) as No_dp,
count(distinct a.DIM_PERSON_ID) as no_ppl
from
SERVICE_PROVISIONS a
inner join date_tbl d on CONVERT(VARCHAR(35),a.start_dttm,112) = d.dim_date_id
where
a.dim_person_id >0
and year = 2018
group by
month,
monthname,
year
my output is this
month monthname year No_dp no_ppl
1 January 2018 142 1604
2 February 2018 111 1526
3 March 2018 133 1636
4 April 2018 1107 3829
5 May 2018 140 1575
6 June 2018 131 1389
7 July 2018 200 893
8 August 2018 2 73
9 September 2018 1 32
10 October 2018 2 21
11 November 2018 2 21
12 December 2018 2 19
So my question is - the customer wants to see how many services were open (using start date and end date) during the previous 12 months (not how many were started, but how many were current and not ended). This is fine when using the current month, however they want to show this also for the previous 12 months as a rolling dynamic figure.
So for example this month in July they want to see how many services were open during the last 12 months. Last month June, they want to see how many services were open during the 12 months previous to June and so on for the previous 12 months.
The table needs to have the month name for the last 12 months and in a column show the number of services that were open in the previous 12 months next to that month.
I hope that makes sense, sorry if it doesn't, feel free to ask questions and I will try to clarify.
The output needs to look something like the current output table, but it is currently only showing how many services were started within that month, which isn't what we want.
The date table is a reference table which has different date formats etc. It can be used or added to if needed.
I've had to make several assumptions about your data. Hopefully the query I'll show in a minute will be easy for you to adjust if any of these are wrong:
I am guessing by its name that start_dttm is a datetime or datetime2 column.
I assume there is a corresponding column called end_dttm that gives the end date/time of a service, and that a null in this column would indicate that a service has not yet ended.
My best guess as to what it means for a service to be "open" in a given month is that it began sometime either within or prior to that month, and has not ended by the time that month is over.
I assume from your original query that multiple services having the same dim_person_id do not represent distinct services.
Since I don't know what's in your date_tbl, I'll show an example that doesn't require it. Consider the following query:
select
BeginDate = dateadd(month, -1, dateadd(day, 1, eomonth(getdate(), -Offset.X))),
EndDate = dateadd(day, 1, eomonth(getdate(), -Offset.X))
from
(values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11)) Offset(X)
This will give you 12 records, representing the current month and each of the 11 preceding months. Note that my EndDate here is not actually the last day of the month, but the first day of the following month. I've done this because of assumption 1 above; since your service dates may have time components, I'll determine whether they fall in a given month by checking if their dates are strictly earlier than the start of the following month. Here's what that query gives me:
BeginDate EndDate
2018-07-01 2018-08-01
2018-06-01 2018-07-01
2018-05-01 2018-06-01
2018-04-01 2018-05-01
2018-03-01 2018-04-01
2018-02-01 2018-03-01
2018-01-01 2018-02-01
2017-12-01 2018-01-01
2017-11-01 2017-12-01
2017-10-01 2017-11-01
2017-09-01 2017-10-01
2017-08-01 2017-09-01
Now I'll join the above result set to your SERVICE_PROVISIONS data, looking for records in each month that have dim_person_id > 0 (from your original query) and which satisfy assumption 3 above.
-- Some sample data (assumptions 1 & 2)
declare #SERVICE_PROVISIONS table (dim_person_id bigint, start_dttm datetime, end_dttm datetime);
insert #SERVICE_PROVISIONS values
(1, '20180101', '20180315'),
(1, '20180101', '20180315'),
(2, '20171215', '20180520');
-- The CTE defines the months we'll report on, as described earlier.
with MonthsCTE as
(
select
BeginDate = dateadd(month, -1, dateadd(day, 1, eomonth(getdate(), -Offset.X))),
EndDate = dateadd(day, 1, eomonth(getdate(), -Offset.X))
from
(values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11)) Offset(X)
)
-- This query matches the months from the CTE against the applicable services.
select
[Month] = datepart(month, M.BeginDate),
[MonthName] = datename(month, M.BeginDate),
[Year] = datepart(year, M.BeginDate),
ServicesOpen = count(distinct S.dim_person_id) -- Assumption 4
from
MonthsCTE M
left join #SERVICE_PROVISIONS S on
S.dim_person_id > 0 and
S.start_dttm < M.EndDate and -- Assumption 3
(
S.end_dttm >= M.EndDate or
S.end_dttm is null -- Assumption 2
)
group by
M.BeginDate,
M.EndDate
order by
M.BeginDate;
Note that I moved the dim_person_id > 0 from the WHERE clause to the JOIN so that each of the 12 months will still appear in the result set even if there were no services open during that time. Results:
Month MonthName Year ServicesOpen
8 August 2017 0
9 September 2017 0
10 October 2017 0
11 November 2017 0
12 December 2017 1
1 January 2018 2
2 February 2018 2
3 March 2018 1
4 April 2018 1
5 May 2018 0
6 June 2018 0
7 July 2018 0
something a bit like this - if you can write a query to get the value you want for a row in your ootput, then use cross apply to link to that query. Counting records that have an open record before the month, but no close record before the month seems feasible
SELECT IQ. *, OA.SERVICE_PROVISIONS FROM (select
month,
monthname,
year,
a.dim_person_id dim_person_id,
count(distinct case when a.dim_service_type_id_desc like '%Direct Payment%' then a.DIM_PERSON_ID else null end) as No_dp,
count(distinct a.DIM_PERSON_ID) as no_ppl
from
SERVICE_PROVISIONS a
inner join date_tbl d on CONVERT(VARCHAR(35),a.start_dttm,112) = d.dim_date_id
where
a.dim_person_id >0
and year = 2018
group by
month,
monthname,
year) IQ
CROSS APPLY
(SELECT count(0) OpenThings FROM SERVICE_PROVISIONS SP1 WHERE
(sp1.startdate < DATEFROMPARTS(IQ.year,iq.month,1)
AND
sp1.enddate is null or sp1.enddate > DATEFROMPARTS(IQ.year,iq.month,1)) and sp1.dim_person_id = iq.dim_person_id
) AS OA

SQL Query to provide a count of jobs that were open grouped by week, month, year for the last 12 months

Given the following data:
Job CreatedDate ClosedDate
ID6 2014-06-04 01:51:47.060 NULL
ID7 2014-06-05 00:25:35.187 NULL
ID43 2014-06-16 05:17:18.803 2014-06-26 15:00:15.190
ID72 2014-06-20 04:00:07.733 2014-06-20 04:12:18.770
ID84 2014-06-27 16:01:18.953 NULL
ID74 2014-06-20 04:05:42.843 NULL
ID68 2014-06-20 03:46:52.653 2014-06-20 03:52:47.540
ID88 2014-07-03 03:47:55.407 NULL
ID64 2014-06-19 07:29:37.060 NULL
ID104 2014-07-08 02:59:58.337 2014-07-15 15:00:15.543
ID106 2014-07-08 03:02:29.710 2014-07-16 11:04:19.230
ID130 2014-07-10 04:30:20.900 NULL
ID132 2014-07-10 04:32:20.243 NULL
ID150 2014-07-15 20:59:06.077 2014-07-15 21:10:19.490
.
.
.
Etc.
I need to write a query that will group records by week, month, and year. A count of the number of records that were in an Open state at the end of each week (Sunday) needs to be returned.
The difficulty arises in determining if a job was in an Open state at the end of a particular week. I imagine the logic goes something like this: A job was open if the CreatedDate is less than or equal to the end of the week and the ClosedDate is after the end of the week or ClosedDate is NULL. A job can remain open over many weeks.
The output should look as follows.
Week Month Year Count
23 6 2014 80
24 6 2014 36
25 6 2014 71
26 6 2014 0
27 7 2014 25
28 7 2014 180
So, at the end of week 23 there were 80 jobs that were still open. Where a week has no records the count should return 0. Only records that were created 12 months from the time the query is executed should be returned. The query is executed every week and used to build a rolling 12 month report. I am using Microsoft SQL Server 2012.
I’ll give an example:
At the beginning of week 1 there are no jobs in the table. During week 1, 50 jobs are opened and 30 are closed which means that 20 are in an Open state at the end of the week.
During week 2, a further 50 jobs are opened and 40 are closed which means that 30 are in an Open state (when you add the 20 from last week and the 10 from this week) at the end of the week. Some of the jobs closed in week 2 were created in week 1 and some of the open jobs are still from week 1.
During week 3, a further 50 jobs are opened and 40 are closed which means that 40 are in an Open state at the end of the week. Some of the jobs closed in week 3 were created in weeks 1 and 2 and some of the open jobs are still from weeks 1 and 2.
And so on for a 12 month period.
When I run the query at the end of week 3 I want to know that at the end of week 1 there were 20 jobs open and at the end of week 2 there were 30 and at the end of week 3 there were 40. You can’t rely on the ClosedDate being NULL because even thought it was at the end of week 1 it may have been closed during week 3 and now has a ClosedDate. As I mentioned above, I think the logic that needs to be used is: A job was in the Open state at the end of a week if the CreatedDate is less than or equal to the end of the week and the ClosedDate is after the end of the week or ClosedDate is NULL.
So, at the end of week 3, when the query is run, the data that I would like to receive would look like:
Week Month Year Count
1 1 2014 20
2 1 2014 30
3 1 2014 40
A manual way of achieving what I need is to run a simple query at the end of each week that counts the number of jobs that have a ClosedDate of NULL. I then manually enter the week, month, year, and count into a table and use that table as a source for reporting. I was hoping that a more automated process could be achieved.
Thanks in advance
Hope this is what you are looking for..
DECLARE #S INT = (SELECT CAST(CAST(MIN([CREATEDDATE]) AS DATETIME) AS INT) FROM [DBO].[YOURTABLE] WHERE [CLOSEDDATE] IS NULL)
DECLARE #E INT = (SELECT CAST(CAST(MAX([CREATEDDATE]) AS DATETIME) AS INT) FROM [DBO].[YOURTABLE] WHERE [CLOSEDDATE] IS NULL)
DECLARE #TAB TABLE (ID INT PRIMARY KEY IDENTITY(1,1), DT DATETIME)
WHILE #S <= #E
BEGIN
INSERT INTO #TAB
SELECT CAST(#S AS DATETIME)
SET #S = #S + 1
END
SELECT MAIN.WEEK,Main.MONTH,Main.YEAR,
LU.COUNT
FROM (
SELECT DATEPART(YEAR,DT) YEAR,
DATEPART(MONTH,DT) MONTH,
DATEPART(WEEK,DT) WEEK
FROM #TAB
GROUP BY DATEPART(YEAR,DT),
DATEPART(MONTH,DT),
DATEPART(WEEK,DT)) MAIN
LEFT JOIN
(
SELECT DATEPART(YEAR,[CREATEDDATE]) YEAR,
DATEPART(MONTH,[CREATEDDATE]) MONTH,
DATEPART(WEEK,[CREATEDDATE]) WEEK,
COUNT(*) COUNT
FROM [DBO].[YOURTABLE]
WHERE [CLOSEDDATE] IS NULL
GROUP BY DATEPART(YEAR,[CREATEDDATE]),
DATEPART(MONTH,[CREATEDDATE]) ,
DATEPART(WEEK,[CREATEDDATE])) LU
ON MAIN.YEAR = LU.YEAR
AND MAIN.MONTH = LU.MONTH
AND MAIN.WEEK = LU.WEEK
ORDER BY MAIN.YEAR,
MAIN.MONTH,
MAIN.WEEK