Oracle SQL - Creating Multiple Ranges for Date Possibilities in a Query - sql

I have this query:
Select *
From Player_Chkin_Cs
That spits out the result:
Player_ID CS_ID CS_LISTING_ID CS_COMP_NAME PT_ADD CREATE_DTIME UUID
179364 300 60132 Wilshire 3 22-DEC-10 (null)
179364 320 68968 Wilshire 30 28-JAN-10 (null)
132489 200 55168 Wilshire 13 03-Jan-10 (null)
132489 900 65478 Wilshire 23 15-Feb-10 (null)
I want to create a query that returns the player_ids of only players who have create_dtimes that fall in both the ranges of 01-Dec-10 to 31-Dec-10 AND 01-Jan-10 to 31-Jan-10.(aka only Player_ID 179364 would show up in the results of this example)
Please let me know if you have any suggestions!

One option would be
SELECT player_id,
COUNT(DISTINCT trunc(create_dtime, 'MM')) num_months
FROM player_chkin_cs
WHERE trunc(create_dtime,'MM') IN (date '2010-12-01', date '2010-01-01')
GROUP BY player_id
HAVING COUNT(DISTINCT trunc(create_dtime, 'MM')) = 2

Related

combine two table with different content to make a table where each id has two rows in bigquery

hope you can help me with this. so i have one table that contains value
user_id
Monday.
Tuesday
Wednesday
aa11
100
164
284
bb22.
223
143
346
and another table that contains count
user_id
Monday.
Tuesday
Wednesday
aa11
2
3
4
bb22
5
2
3
how can i combine both so it looks like this?
user_id
type
Monday.
Tuesday
Wednesday
aa11
value
100
164
284
aa11
count
2
3
4
bb22.
value
223
143
346
bb22
count
5
2
3
is it even a good practice to pivot long like this or should i just pivot wide so there would be columns monday_value, monday_count, tuesday_value, tuesday_count, etc?
Simple union? :
select * from (
select user_id, 'value' as type,Monday.,Tuesday,Wednesday
from table1
union all
select user_id, 'count' as type,Monday.,Tuesday,Wednesday
from table2
) t
You can use simple way as given in answer by #eshirvana.
Or as per your ask, if you want to do it horizontally you can do it following way:
WITH week_value AS
(
SELECT 1 as user, 100 as monday
UNION ALL SELECT 2 as user, 200 as monday
),
week_count as (
SELECT 1 as user, 10 as monday
UNION ALL SELECT 2 as user, 2 as monday
)
select A.user, A.monday as monday_value, B.monday as monday_count
from week_value as A
FULL JOIN week_count as B on A.user = B.user

How to calculate total worktime per week [SQL]

I have a table of EMPLOYEES that contains information about the DATE and WORKTIME per that day. Fx:
ID | DATE | WORKTIME |
----------------------------------------
1 | 1-Sep-2014 | 4 |
2 | 2-Sep-2014 | 6 |
1 | 3-Sep-2014 | 5.5 |
1 | 4-Sep-2014 | 7 |
2 | 4-Sep-2014 | 4 |
1 | 9-Sep-2014 | 8 |
and so on.
Question: How can I create a query that would allow me to calculate amount of time worked per week (HOURS_PERWEEK). I understand that I need a summation of WORKTIME together with grouping considering both, ID and week, but so far my trials as well as googling didnt yield any results. Any ideas on this? Thank you in advance!
edit:
Got a solution of
select id, sum (worktime), trunc(date, 'IW') week
from employees
group by id, TRUNC(date, 'IW');
But will need somehow to connect that particular output with DATE table by updating a newly created column such as WEEKLY_TIME. Any hints on that?
You can find the start of the ISO week, which will always be a Monday, using TRUNC("DATE", 'IW').
So if, in the query, you GROUP BY the id and the start of the week TRUNC("DATE", 'IW') then you can SELECT the id and aggregate to find the SUM the WORKTIME column for each id.
Since this appears to be a homework question and you haven't attempted a query, I'll leave it at this to point you in the correct direction and you can complete the query.
Update
Now I need to create another column (lets call it WEEKLY_TIME) and populate it with values from the current output, so that Sep 1,3,4 (for ID=1) would all contain value 16.5, specifying that on that day (that is within the certain week) that person worked 16.5 in total. And for ID=2 it would then be a value of 10 for both Sep 2 and 4.
For this, if I understand correctly, you appear to not want to use aggregation functions and want to use the analytic version of the function:
select id,
"DATE",
trunc("DATE", 'IW') week,
worktime,
sum (worktime) OVER (PARTITION BY id, trunc("DATE", 'IW'))
AS weekly_time
from employees;
Which, for the sample data:
CREATE TABLE employees (ID, "DATE", WORKTIME) AS
SELECT 1, DATE '2014-09-01', 4 FROM DUAL UNION ALL
SELECT 2, DATE '2014-09-02', 6 FROM DUAL UNION ALL
SELECT 1, DATE '2014-09-03', 5.5 FROM DUAL UNION ALL
SELECT 1, DATE '2014-09-04', 7 FROM DUAL UNION ALL
SELECT 2, DATE '2014-09-04', 4 FROM DUAL UNION ALL
SELECT 1, DATE '2014-09-09', 8 FROM DUAL;
Outputs:
ID
DATE
WEEK
WORKTIME
WEEKLY_TIME
1
2014-09-01 00:00:00
2014-09-01 00:00:00
4
16.5
1
2014-09-03 00:00:00
2014-09-01 00:00:00
5.5
16.5
1
2014-09-04 00:00:00
2014-09-01 00:00:00
7
16.5
1
2014-09-09 00:00:00
2014-09-08 00:00:00
8
8
2
2014-09-04 00:00:00
2014-09-01 00:00:00
4
10
2
2014-09-02 00:00:00
2014-09-01 00:00:00
6
10
db<>fiddle here
edit: answer submitted without noticing "Oracle" tag. Otherwise, question answered here: Oracle SQL - Sum and group data by week
Select employee_Id,
DATEPART(week, workday) as [Week],
sum (worktime) as [Weekly Hours]
from WORK
group by employee_id, DATEPART(week, workday)
https://dbfiddle.uk/?rdbms=sqlserver_2019&fiddle=238b229156a383fa3c466b6c3c2dee1e

SQL Querying of Data by grouping with only one main variable(Store) and finding the percentage of customers in other variable

Tables - Store
Stores
Date
Customer_ID
A
01/01/2020
1111
C
01/01/2020
1111
F
02/01/2020
1234
A
02/01/2020
1111
A
02/01/2020
2222
Tables - Customer
Customer_ID
Age_Group
Income_Level
1111
26-30
Low
1234
25 and below
Mid
2222
31-60
High
I want to know how I can get this output.
Stores
Age_Group
Percentage_by_Age
Income_Level
Percentage_By_Income
A
25 and below
10
Low
80
A
25 and below
10
Mid
10
A
25 and below
10
High
10
A
26 - 30
42
Low
15
A
26 - 30
42
Mid
65
A
26 - 30
42
High
20
A
31 - 60
48
Low
30
A
31 - 60
48
Mid
50
A
31 - 60
48
High
20
I am using SQL to query from different tables.
First I need to aggregate the number of customers by stores, then in each store, I want to find out how many customers visited Store A in a particular age group(25 and below), and how many of them are in which income level.
May I know how I can go about solving this query?
Thanks.
My current solution/thought process
SELECT
stores AS Stores,
Age_Group AS Age,
Income_Level AS Income
COUNT(DISTINCT(Customer_ID)) AS Number_of_Customers
FROM tables JOIN tables....
GROUP BY Stores, Ages, Income;
And then manually calculating the percentages.
But it doesn't seem right.
Is there a way to produce an example output table using just SQL?
As per your requirement, Common Table Expressions can be used . You can use below code to get the expected output.
WITH
data_for_percent_by_income AS (
SELECT
COUNT(customer_id) AS cus_count_in_per_income_level_and_agegrp,
Age_group AS age_g,income_level AS inc_lvl
FROM
`project.dataset.Customer2`
WHERE
customer_id IN (
SELECT customer_id
FROM
`project.dataset.Store5`
WHERE stores='A')
GROUP BY
Age_group,income_level),tot_cus_in_defined_income_level AS (
SELECT
COUNT(customer_id) AS cus_count_in_per_income_level,Age_group AS ag
FROM
`project.dataset.Customer2`
WHERE
customer_id IN (
SELECT
customer_id
FROM
`project.dataset.Store5`
WHERE stores='A')
GROUP BY
Age_group),
tot_cus_storeA AS(
SELECT
COUNT(*) AS tot_cus_in_A
FROM
`project.dataset.Customer2`
WHERE customer_id IN (
SELECT customer_id
FROM
`project.dataset.Store5`
WHERE stores='A') ),
final_view AS(
SELECT
ROUND(cus_count_in_per_income_level_and_agegrp*100/cus_count_in_per_income_level) AS p_by_inc,
age_g,inc_lvl
FROM
data_for_percent_by_income
INNER JOIN
tot_cus_in_defined_income_level
ON
data_for_percent_by_income.age_g=tot_cus_in_defined_income_level.ag )
SELECT
stores,tot_cus_in_defined_income_level.ag AS age_group,income_level,
ROUND(cus_count_in_per_income_level*100/tot_cus_in_A) AS percentage_by_age,
p_by_inc AS percentage_by_income
FROM
tot_cus_in_defined_income_level,tot_cus_storeA,`project.dataset.Customer2`,`project.dataset.Store5`
INNER JOIN
final_view
ON
age_group=final_view.age_g AND income_level=final_view.inc_lvl
WHERE
tot_cus_in_defined_income_level.ag = Age_group AND stores='A'
GROUP BY
stores,percentage_by_age,age_group,income_level,percentage_by_income
ORDER BY Age_group
I have attached the screenshots of the input table and output table.
Customer Table
Store Table
Output Table
SELECT
s.Stores AS Stores,
c.age_group AS Age,
a.income_level AS Affluence,
CAST(COUNT(DISTINCT c.Customer_ID) AS numeric)*100/SUM(CAST(COUNT(DISTINCT c.Customer_ID) AS numeric)) OVER(PARTITION BY s.Stores ) AS Perc_of_Members
This is what I did in the end.

SQL query to find the avg salary based on the nearest client dob's

I have a requirement with a below table.
Conditions:
I have to take the average of salaries clients, if the client has serial 3 days date of birth gap.
If there are no nearest 3 day dob's gap between the gap between the clients, then no need to take that client into consideration.
Example:
in the below table
client 17 has previous clientid's WITH serial dob's with 1day gap -> in this case I'll TAKE salary AVG FOR 17 BY taking 15,16 & 17 salaries.
client 18 has previous clientid's WITH serial dob's -> in this case I'll TAKE salary AVG FOR 18 BY taking 16,17 & 18 salaries.
Table:
JobType ClientID ClinetDOB's Slaries
.net 1 2012-03-14 300
.net 2 2012-04-11 400
.net 3 2012-04-12 200
.net 4 2012-07-29 400
.net 5 2012-08-17 1200
.net 6 2012-08-18 1400
.net 7 2012-08-19 1400
java 8 2012-04-10 400
java 9 2012-07-29 400
java 10 2012-07-30 600
java 11 2012-08-14 1200
java 12 2012-08-15 1800
java 13 2012-08-16 1100
java 14 2012-09-17 1200
java 15 2012-08-18 2400
java 16 2012-08-19 2400
java 17 2012-08-20 2400
java 18 2012-08-21 1500
Result Should looks LIKE this:-
JobType ClientID ClinetDOB's AVG(Slaries)
.net 7 2012-08-19 1333
Java 13 2012-08-16 1366 --This avg of 5,6,7 clientsId's(because they have serial 3days dob's)
Java 17 2012-08-20 2400 --This avg of 15,16,17 clientsId's(because they have serial 3days dob's)
Java 18 2012-08-21 2100 --This avg of 16,17,18 clientsId's(because they have serial 3days dob's)
Below query giving the some messup results.
select t1.ClientID,
t1.ClinetDOBs,
(t1.Slaries + sum (t2.Slaries)) / (count (*) + 1) Avg_Slaries
from table1 t1
inner join table1 t2
on (t1.ClinetDOBs = dateadd(day, 3, t2.ClinetDOBs) and t1.jobtype = t2.jobtype)
group by t1.ClientID,
t1.ClinetDOBs,
t1.Slaries
Please help.
Thank You In advance!
You might try this - difference is that from t2 are taken rows from previous three days, which include current row being tested so no double-summing is needed. Also ˙having` removes rows that reference themselves only.
select t1.ClientID,
t1.ClinetDOBs,
avg(t2.Slaries) Avg_Slaries
from table1 t1
inner join table1 t2
on t1.ClinetDOBs >= t2.ClinetDOBs
and t1.ClinetDOBs <= dateadd(day, 3, t2.ClinetDOBs)
and t1.jobtype = t2.jobtype
group by t1.ClientID,
t1.ClinetDOBs
having count(*) > 1
You can see it on your last data here.
The following query joins in each of the three preceding records. The joins both bring in the data and act as a filter to ensure that there are three:
select tmain.ClientID, tmain.ClinetDOBs,
sum(tmain.slaries + t1.slaries + t2.slaries)/3.0 as avg_slaries
from table1 tmain join
table1 t1
on t1.ClinetDOBs = dateadd(day, -1, tmain.ClinetDOBs) and
t1.jobtype = tmain.jobtype join
table t2
on t2.ClinetDOBs = dateadd(day, -2, tmain.ClinetDOBs) and
t2.jobtype = tmain.jobtype
group by tmain.ClientID, tmain.ClinetDOBs, tmain.Slaries
You question seems odd. Why do the dates have to be sequential and why do they all have to be there? What happens if there are multiple people on the same date and job title?
Try
select t1.ClientID,
t1.ClinetDOBs,
avg(t2.Slaries)
from table1 t1
inner join table1 t2
on t2.ClinetDOBs >= t1.ClinetDOBs)
t2.ClinetDOBs <= dateadd(day, 3, t1.ClinetDOBs)
and t1.jobtype = t2.jobtype
group by t1.ClientID,
t1.ClinetDOBs

SELECT all at once

I want to select patient_id and date difference from below table:
p_id TreatmentDate
15 2008-05-01
15 2008-05-03
15 2008-05-05
15 2008-05-07
16 2008-05-01
16 2008-05-03
16 2008-05-05
16 2008-05-09
16 2008-05-11
17 2008-05-03
17 2008-05-05
17 2008-05-07
I want to have this result:
p_id Day Difference
15 6 Days
16 10 Days
17 4 Days
Do you have any offer that can generate this result in sql statement?
This should work in general
select p_id, max(TreatmentDate) - min(TreatmentDate) from
patientsTable group by p_id
more specifically, for MSSQL Server
select p_id, DATEDIFF(D, MIN(TreatmentDate), MAX(TreatmentDate)) from
patientsTable group by p_id
MS SQL Server:
SELECT
p_id,
STR(DATEDIFF(DAY, MIN(TreatmentDate), MAX(TreatmentDate))) + ' Days' AS DayDifference
FROM
table
GROUP BY
p_id
MS SQL:
select
p_id,
datediff(d, min(TreatmentDate), max(TreatmentDate)) AS DayDifference
from
patientsTable
group by
p_id;
This will work:
SELECT p_id, CONCAT(max(TreatmentDate) - min(TreatmentDate),' Days') as "Day Difference"
FROM
patient_info
GROUP BY p_id;
Given this schema/data:
CREATE TABLE patient_info (
p_id INT,
TreatmentDate DATE
);
INSERT INTO patient_info
VALUES
(15,'2008-05-01'),
(15,'2008-05-03'),
(15,'2008-05-05'),
(15,'2008-05-07'),
(16,'2008-05-01'),
(16,'2008-05-03'),
(16,'2008-05-05'),
(16,'2008-05-09'),
(17,'2008-05-03'),
(17,'2008-05-05'),
(17,'2008-05-07');
+------+----------------+
| p_id | Day Difference |
+------+----------------+
| 15 | 6 Days |
| 16 | 8 Days |
| 17 | 4 Days |
+------+----------------+
3 rows in set (0.00 sec)
Please let me know if you need more help.