SQL - How to combine 3 dates from 3 different tables (BigQuery) [closed] - sql

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 1 year ago.
Improve this question
Need to have one view for each agent, and want to aggregate all dates to include all metrics
Basic Information:-
In the productivity table carries the information like as follows:
| Handled_DATE | Agent_Email | Handled | Missed
|:-----------: |:-------------: |:--------:|:------:|
|2013-11-05 | Agent_01#google.com | 80 | 9
|2013-11-06 | Agent_02#google.com | 60 | 15
|2013-11-07 | Agent_03#google.com | 70 | 7
|2013-11-08 | Agent_04#google.com | 55 | 13
|2013-11-09 | Agent_01#google.com | 73 | 5
|2013-11-10 | Agent_01#google.com | 64 | 14
In the Quality table carries the information like this:
| Monitored_DATE | Agent_Email | Bussiness_Critical | Failed
|:-----------: |:-------------: |:-------------: |:-----------:|
|2013-11-05 | Agent_01#google.com | 2 | 2
|2013-11-06 | Agent_01#google.com | 1 | 1
|2013-11-07 | Agent_01#google.com | 4 | 4
|2013-11-08 | Agent_04#google.com | 1 | 1
In the Absentieesm table it carries the information like this:
| Attendance_Date | Agent_Email | Attendance | Late_min
|:-----------: |:-------------: |:----------:|:-----------:|
|2013-11-05 | Agent_01#google.com | Attend | 9
|2013-11-06 | Agent_01#google.com | Sick | 0
|2013-11-07 | Agent_01#google.com | Sick | 0
|2013-11-08 | Agent_04#google.com | 55 | 13
|2013-11-10 | Agent_01#google.com | Attend | 0
Desired Output
| DATE | Agent_Email | Handled | Missed | Business_Critical | Failed |Attendance|Late_min
|:---------- |:-------------: |:-------:|:------:|:-----------------:|:-----: |:--------:|:------:|
|2013-11-05 | Agent_01#google.com | 80 | 9 | 2 | 2 | Attend | 9
|2013-11-06 | Agent_01#google.com | 0 | 0 | 1 | 1 | sick | 0
|2013-11-07 | Agent_01#google.com | 0 | 0 | 4 | 4 | sick | 0
|2013-11-08 | Agent_01#google.com | 0 | 0 | 0 | 0 | sick | 0
|2013-11-09 | Agent_01#google.com | 73 | 5 | 0 | 0 | NA | 0
|2013-11-10 | Agent_01#google.com | 64 | 14 | 0 | 0 | Attend | 0

Try this code - let me know if it helps.
WITH Date AS
(
SELECT DISTINCT date1
FROM
(SELECT p.handled_date AS date1
FROM `productivity` AS p
UNION ALL
SELECT q.Monitored_DATE AS date1
FROM `Quality` AS q
UNION ALL
SELECT a.Attendance_Date AS date1
FROM `Absentieesm` AS a
)
),
Agent AS
(
SELECT DISTINCT Agent_Email
FROM
(SELECT p.Agent_Email AS Agent_Email
FROM `productivity` AS p
UNION ALL
SELECT q.Agent_Email AS Agent_Email
FROM `Quality` AS q
UNION ALL
SELECT a.Agent_Email AS Agent_Email
FROM `Absentieesm` AS a
)
)
SELECT DISTINCT
Date1,
Agent.Agent_Email,
IFNULL(Handled, 0) AS Handled,
IFNULL(Missed, 0) AS Missed,
IFNULL(Business_Critical, 0) AS Business_Critical,
IFNULL(Failed, 0) AS Failed,
IFNULL(Attendance, NULL) Attendance,
IFNULL(Late_min, 0) AS Late_min
FROM
Agent, Date
LEFT OUTER JOIN
`productivity` p ON p.Agent_Email = Agent.Agent_Email
AND p.Handled_DATE = Date.Date1
LEFT OUTER JOIN
`Quality` q ON q.Agent_Email = Agent.Agent_Email
AND q.Monitored_DATE = Date.Date1
LEFT OUTER JOIN
`Absentieesm` a ON a.Agent_Email = Agent.Agent_Email
AND a.Attendance_Date = Date.Date1
ORDER BY
Agent_Email, Date1
```

Join the tables with Agent_Email and respective dates as follows:
SELECT p.handled_date as date,
p.Agent_Email, p.Handled, p.Missed
q.Business_Critical, q.Failed
a.Attendance, a.Late_min
FROM Productivity as p
LEFT JOIN Quality as q
ON p.Agent_Email = q.Agent_Email
AND p.handled_date = q.Monitored_DATE
LEFT JOIN absentieesm as a
ON p.Agent_Email = a.Agent_Email
AND p.handled_date = a.Attendance_DATE
Note - Keep the table which has most of the Agents as LEFT TABLE

Related

Generate multiple record from existing records based on interval columns [from and to]

I have 2 types of score [M,B] in column 3, if a type is M, then the score is either an S[scored] or SB[bonus scored] in column 6. Every interval [from_hrs - to_hrs] for a type B must have a corresponding SB for type M, thus, an interval for a type B cannot have a score of S for a type M. I have several records that were unfortunately captured as seen in the table below.
CREATE TABLE SCORE_TBL
(
ID int IDENTITY(1,1) PRIMARY KEY,
PERSONID_FK int NOT NULL,
S_TYPE varchar(50) NULL,
FROM_HRS int NULL,
TO_HRS int NULL,
SCORE varchar(50) NULL,
);
INSERT INTO SCORE_TBL(PERSONID_FK,S_TYPE,FROM_HRS,TO_HRS,SCORE)
VALUES
(1, 'M' , 0,20, 'S'),
(1, 'B',6, 8, 'B'),
(2, 'B',0, 2, 'B'),
(2, 'M',0,20, 'S'),
(2, 'B', 10,13, 'B'),
(2, 'B', 18,20, 'B'),
(2, 'M', 13,18, 'S');
| ID | PERSONID_FK |S_TYPE| FROM_HRS | TO_HRS | SCORE |
|----|-------------|------|----------|--------|-------|
| 1 | 1 | M | 0 | 20 | S |
| 2 | 1 | B | 6 | 8 | B |
| 3 | 2 | B | 0 | 2 | B |
| 4 | 2 | M | 0 | 20 | S |
| 5 | 2 | B | 10 | 13 | B |
| 6 | 2 | B | 18 | 20 | B |
| 7 | 2 | M | 13 | 18 | S |
I want the data to look like this
| ID | PERSONID_FK |S_TYPE| FROM_HRS | TO_HRS | SCORE |
|----|-------------|------|----------|--------|-------|
| 1 | 1 | M | 0 | 6 | S |
| 2 | 1 | M | 6 | 8 | SB |
| 3 | 1 | B | 6 | 8 | B |
| 4 | 1 | M | 8 | 20 | S |
| 5 | 2 | B | 0 | 2 | B |
| 6 | 2 | M | 0 | 2 | SB |
| 7 | 2 | M | 2 | 10 | S |
| 8 | 2 | B | 10 | 13 | B |
| 9 | 2 | M | 10 | 13 | SB |
| 10 | 2 | M | 13 | 18 | S |
| 11 | 2 | B | 18 | 20 | B |
| 12 | 2 | S | 18 | 20 | SB |
Any ideas on how to generate this data in SQL Server select statement? Visually, this what am trying to get.
Tricky part here is that interval might need to be split in several pieces like 0..20 for person 2.
Window functions to the rescue. This query illustrates what you need to do:
WITH
deltas AS (
SELECT personid_fk, hrs, sum(delta_s) as delta_s, sum(delta_b) as delta_b
FROM (SELECT personid_fk, from_hrs as hrs,
case when score = 'S' then 1 else 0 end as delta_s,
case when score = 'B' then 1 else 0 end as delta_b
FROM score_tbl
UNION ALL
SELECT personid_fk, to_hrs as hrs,
case when score = 'S' then -1 else 0 end as delta_s,
case when score = 'B' then -1 else 0 end as delta_b
FROM score_tbl) _
GROUP BY personid_fk, hrs
),
running AS (
SELECT personid_fk, hrs as from_hrs,
lead(hrs) over (partition by personid_fk order by hrs) as to_hrs,
sum(delta_s) over (partition by personid_fk order by hrs) running_s,
sum(delta_b) over (partition by personid_fk order by hrs) running_b
FROM deltas
)
SELECT personid_fk, 'M' as s_type, from_hrs, to_hrs,
case when running_b > 0 then 'SB' else 'S' end as score
FROM running
WHERE running_s > 0
UNION ALL
SELECT personid_fk, s_type, from_hrs, to_hrs, score
FROM score_tbl
WHERE s_type = 'B'
ORDER BY personid_fk, from_hrs;
Step by step:
deltas is union of two passes on score_tbl - one for start and one for end of score/bonus interval, creating a timeline of +1/-1 events
running calculates running total of deltas over time, yielding split intervals where score/bonus are active
final query just converts score codes and unions bonus intervals (which are passed unchanged)
SQL Fiddle here.

Group-by if all field results are true

I have this query:
SELECT
tbl_ord.ord.table,
tbl_ord.ord.n_ord,
player.confirm
FROM
tbl_ord
INNER JOIN
tbl_players ON tbl_ord.player_id = tbl_players.player_ids
WHERE
id_shop = 3
ORDER BY
n_ord ASC
result:
+-----------+-------+---------+
| ord_table | n_ord | confirm |
+-----------+-------+---------+
| 10 | 2 | 1 |
| 10 | 2 | 0 |
| 8 | 3 | 1 |
| 8 | 3 | 1 |
| 4 | 5 | 1 |
| 4 | 5 | 1 |
+-----------+-------+---------+
I'd like get only result with all confirmed users by group-by on ord_table
+-----------+-------+---------+
| ord_table | n_ord | confirm |
+-----------+-------+---------+
| 4 | 5 | 1 |
| 8 | 3 | 1 |
+-----------+-------+---------+
Thanks!
You can probably use not exists:
SELECT o.ord_table, o.ord.n_ord,
1 as confirm
FROM tbl_ord o
WHERE NOT EXISTS (SELECT 1
FROM tbl_players p
WHERE o.player_id = p.player_ids AND
?.id_shop = 3 AND -- not sure what table this comes from
p.confirm = 0
)
ORDER BY o.n_ord ASC;
The advantage of this approach is that it avoids aggregating at the outer level. This, in turn, means that it can make better use of indexes, including using an index to potentially avoid sorting.
Use HAVING:
SELECT
tbl_ord.ord.table,
tbl_ord.ord.n_ord,
MIN(player.confirm)
FROM tbl_ord
INNER JOIN tbl_players ON tbl_ord.player_id = tbl_players.player_ids
WHERE id_shop = 3
GROUP BY tbl_ord.ord.table, tbl_ord.ord.n_ord,
HAVING MIN(player.confirm) = 1
ORDER BY n_ord ASC

How to use SQL Join with multiple fields and find sum of values

How to SQL Join with multiple fields and sum of values .
As per my query i am getting duplicates
job_main (table)
+-----+------+------+------------+
| Loc | Year | Wo | total_cost |
+-----+------+------+------------+
| 8 | 2018 | 2402 | 1175 |
+-----+------+------+------------+
Job_line (table)
+-----+------+------+------------+------------+-----------+-----------+-----------+
| loc | Year | Wo | labor_cost | parts_cost | total_tax | parts_tax | labor_tax |
+-----+------+------+------------+------------+-----------+-----------+-----------+
| 8 | 2018 | 2402 | 0 | 1202.85 | 0 | 0 | 0 |
| 8 | 2018 | 2402 | 0 | -1202.85 | 0 | 0 | 0 |
| 8 | 2018 | 2402 | 0 | 1119.05 | 55.95 | 55.95 | 0 |
+-----+------+------+------------+------------+-----------+-----------+-----------+
Result (Expected)
+-----+------+------+------------+------------+------------+-----------+-----------+-----------+
| Loc | Year | Wo | total_cost | labor_cost | parts_cost | parts_tax | labor_tax | total_tax |
+-----+------+------+------------+------------+------------+-----------+-----------+-----------+
| 8 | 2018 | 2402 | 1175 | 0 | 1119.05 | 55.95 | 0 | 55.95 |
+-----+------+------+------------+------------+------------+-----------+-----------+-----------+
My Query:
SELECT distinct "JOB_LINE""."LOC", "JOB_LINE""."Year", "JOB_LINE""."Wo"
, ISNULL(("JOB_MAIN"."total_cost" ), 0) AS "total_cost", ISNULL(SUM("JOB_LINE""."labor_cost"), 0) AS "labor_cost"
, ISNULL(SUM("JOB_LINE""."labor_tax"), 0) AS "labor_tax" , ISNULL(SUM("JOB_LINE""."parts_cost"), 0) AS "parts_cost"
, ISNULL(SUM("JOB_LINE""."total_tax"), 0) AS "total_tax" , ISNULL(SUM("JOB_LINE""."parts_tax"), 0) AS "parts_tax"
FROM "proto"."emsdba"."JOB_LINE"" "JOB_LINE""
INNER JOIN "proto"."emsdba"."JOB_MAIN" "JOB_MAIN"
ON "JOB_LINE"".LOC="JOB_MAIN".LOC AND "JOB_LINE"".year="JOB_MAIN".year AND "JOB_LINE"".Wo="JOB_MAIN".Wo
GROUP by "JOB_LINE""."LOC", "JOB_LINE""."Year", "JOB_LINE""."Wo","JOB_MAIN"."total_cost"
, "JOB_LINE"".labor_cost, "JOB_LINE"".parts_cost, "JOB_LINE"".total_tax, "JOB_LINE"".parts_tax,"JOB_LINE"".labor_tax
Try with this:
select m.loc,m.year,m.wo,m.total_cost,sum(l.labor_cost),sum(l.parts_cost),sum(l.parts_tax),sum(l.labor_tax),sum(l.total_tax)
from proto.emsdba.job_main m
join proto.emsdba.job_line l
on m.loc=l.loc
and m.year=l.year
and m.wo=l.wo
group by m.loc,m.year,m.wo,m.total_cost
Basically, you group by the fields in the parent table (shared by all the lines) and sum the values of the lines to get a single record for each key (loc/year/wo)
Although you can use join and group by for this, this problem is also a good candidate for apply:
select m.*,
coalesce(labor_cost, 0) as labor_cost,
coalesce(parts_cost, 0) as parts_cost,
coalesce(parts_tax, 0) as parts_tax,
coalesce(labor_tax, 0) as labor_tax,
coalesce(total_tax, 0) as total_tax
from proto.emsdba.job_main m outer apply
(select sum(jl.labor_cost) as labor_cost,
sum(jl.parts_cost) as parts_cost,
sum(jl.parts_tax) as parts_tax,
sum(jl.labor_tax) as labor_tax,
sum(jl.total_tax) as total_tax
from proto.emsdba.job_line jl
where m.loc = jl.loc and
m.year = jl.year and
m.wo = jl.wo
) jl;

SQL: Complex query with subtraction from different cells

I have two tables and I want to combine their data.
The first table
+------------+-----+------+-------+
| BusinessID | Lat | Long | Stars |
+------------+-----+------+-------+
| abc123 | 32 | 74 | 4.5 |
| abd123 | 32 | 75 | 4 |
| abe123 | 33 | 76 | 3 |
+------------+-----+------+-------+
The second table is:
+------------+-----+------+-------+
| BusinessID | day | time | count |
+------------+-----+------+-------+
| abc123 | 1 | 14 | 5 |
| abc123 | 1 | 15 | 6 |
| abc123 | 2 | 13 | 1 |
| abd123 | 4 | 12 | 4 |
| abd123 | 4 | 13 | 8 |
| abd123 | 5 | 11 | 2 |
+------------+-----+------+-------+
So what I want to do is find all the Businesses that are in a specific radius and have more check ins in the next hour than the current.
So the results are
+------------+
| BusinessID |
+------------+
| abd123 |
| abc123 |
+------------+
Because they have more check-ins in the next hour than the previous (6 > 5, 8 > 4)
What is more it would be helpful if the results where ordered by their difference in check-ins number. Ex. ( 8 - 4 > 6 - 5 )
SELECT *
FROM table2 t2
WHERE t2.BusinessID IN (
SELECT t1.BusinessID
FROM table1 t1
WHERE earth_box(ll_to_earth(32, 74), 4000/1.609) #> ll_to_earth(Lat, Long)
ORDER by earth_distance(ll_to_earth(32, 74), ll_to_earth(Lat, Long)), stars DESC
) AND checkin_day = 1 AND checkin_time = 14;
From the above query I can find the businesses in a radius and then find their check-ins in the specified time. Ex. 14. What I need to do now is to find the number of check-ins in the 15 hour (of the same businesses) and find if the number of the check-ins is greater than it was in the previous time.
I think you want something like this:
SELECT
t1.BusinessID
FROM
table1 t1
JOIN
(SELECT
*,
"count" - LAG("count") OVER (PARTITION BY BusinessID, "day" ORDER BY "time") "grow"
FROM
table2
WHERE
/* Some condition on table2 */) t2
ON t1.BusinessID = t2.BusinessID AND t2.grow > 0
WHERE
/* Some condition on table1 */
ORDER BY
t2.grow DESC;

Can't figure out a simple SQL query

Might be very simple, but I've been digging fow a few days now... I just can't figure out how to make this SQL query in Access...
In reference to the tables below, i'm looking for the query that can extract all the ITEMS for a specific Shop (ie 1:Alpha) from a specific GROUP (ie 1:Tools), that are NOT in the report for 2014... in this case ITEMS.IDs 6, 8, 9 and 10!
Tables:
Years
ID | Year
-----------------------------------------------
1 | 2014
2 | 2015
Shops
ID | ShopName
-----------------------------------------------
1 | Alpha
2 | Bravo
Items
ID | StockNbr | Description | GroupID
-----------------------------------------------
1 | 00-1200 | Ratchet 1/4 | 1
2 | 00-1201 | Ratchet 1/2 | 1
3 | 00-1300 | Screwdriver Philips No1 | 1
4 | 01-5544 | Banana | 2
5 | 00-4457 | Apple | 2
6 | 21-8887 | Hammer | 1
7 | 21-6585 | Drill | 1
8 | 21-4499 | Multimeter | 1
9 | 21-5687 | Digital Caliper | 1
10 | 22-7319 | File Set | 1
...
Groups
ID | GroupName
-----------------------------------------------
1 | Tools
2 | Fruits
REPORTS
ID | YearID | ShopID | ItemID
-----------------------------------------------
1 | 1 | 1 | 1
2 | 1 | 1 | 2
3 | 1 | 1 | 3
4 | 1 | 1 | 4
5 | 1 | 1 | 7
6 | 1 | 2 | 5
7 | 1 | 2 | 8
8 | 1 | 2 | 10
I've tried this, but then I realize it doesn't take the shops into consideration, it'll list all items that are not listed in reports, so if reports has an item for shop 2, it won't list it either...
SELECT Items.ID, Items.StockNbr, Items.Description, Items.GroupID, Reports.YearID, Reports.ShopID
FROM Reports
RIGHT JOIN Items ON Reports.ItemID = Items.ID
WHERE (((Items.GroupID)=1) AND ((Reports.UnitID) Is Null))
ORDER BY Items.StockNbr;
Thank you!
I think you're looking for an anti-join. There are several ways to do this. Here's one using not in.
select i.* from items i
where i.GroupId = 1
and i.ID NOT IN (
select ItemID from reports r
where r.ShopID = 1
and r.YearID = 2014
)
If the table Reports does not reference Items.ID then there is no available relationship ShopID or YearID
select *
from items
left join reports on items.id = reports.itemid
where reports.itemid IS NULL