I'm super new to SQL.
I need to run some SQL queries in VBA (Excel) - so I'm using ADO in Excel VBA to access Microsoft ACE OLEDB 12.0 as a provider (which I think - correct me if I'm wrong here - is Access). Currently a work tracking program generates (of interest) a table with columns of User, Start Date, Duration like so (here's a sample snippet):
What the table looks like
Not everyone is doing work on the same day.
I need to return a result that shows, for a given person on all possible working days, the sum of all Duration(s) they worked (then I need to do it again for their admin tasks, and then the rest is maths to understand efficiencies). It'd be great to return zero on days where there is no duration.
I've created a calendar table (with relevant dates in Calendar.Dates). This isn't giving me what I want though....
SELECT
[WorkData].Duration AS Expr1,
[WorkData].User, [Calendar].Dates
FROM
WorkData
RIGHT JOIN
Calendar ON ([WorkData].[Start date] = [Calendar].Dates)
AND ([WorkData].[Start date] = [Calendar].Dates)
GROUP BY
[WorkData].User, [Calendar].Dates, [WorkData].Duration
HAVING
((([WorkData].User) = 'User1'))
ORDER BY
[Calendar].Dates;
Is what I'm trying to do even possible? Any help would be most appreciated.
I can't get any results for the days where someone didn't work.
using two queries to simplify the sql. Assuming:
Durations format is unclear and not relevant to the answer so it is converted to minutes for the example
'Users
-------------------------------------------
| UserID | UserName |
-------------------------------------------
| 1 | User1 |
-------------------------------------------
| 2 | User2 |
-------------------------------------------
'Projects
-------------------------------------------------------------------
| ProjectID | ProjectName | ProjectTypeID |
-------------------------------------------------------------------
| 1 | Client1 | 1 |
-------------------------------------------------------------------
| 2 | Admin1 | 2 |
-------------------------------------------------------------------
| 3 | Client2 | 1 |
-------------------------------------------------------------------
| 4 | Admin2 | 2 |
-------------------------------------------------------------------
'WorkDates
-------------------------------------------
| WorkDateID | WorkDate |
-------------------------------------------
| 1 | 11/1/2021 |
-------------------------------------------
| 2 | 11/2/2021 |
-------------------------------------------
'WorkData
----------------------------------------------------------------------------------------------------------
| ID | UserID | ProjectID | StartDate | Duration |
----------------------------------------------------------------------------------------------------------
| 1 | 1 | 1 | 11/1/2021 | 510 |
----------------------------------------------------------------------------------------------------------
| 2 | 1 | 3 | 11/1/2021 | 720 |
----------------------------------------------------------------------------------------------------------
| 3 | 2 | 2 | 11/1/2021 | 20 |
----------------------------------------------------------------------------------------------------------
| 4 | 2 | 4 | 11/1/2021 | 65 |
----------------------------------------------------------------------------------------------------------
| 5 | 1 | 1 | 11/1/2021 | 10 |
----------------------------------------------------------------------------------------------------------
then: unrelated tables are cross-multiplied so we get every combination of user and WorkDate
'sql
SELECT Users.UserID, Users.UserName, WorkDates.WorkDate
FROM WorkDates, Users;
'results
----------------------------------------------------------------
| UserID | UserName | WorkDate |
----------------------------------------------------------------
| 1 | User1 | 11/1/2021 |
----------------------------------------------------------------
| 1 | User1 | 11/2/2021 |
----------------------------------------------------------------
| 2 | User2 | 11/1/2021 |
----------------------------------------------------------------
| 2 | User2 | 11/2/2021 |
----------------------------------------------------------------
the first query behaves just like a table in a second query so we can add a calculated field to look up and sum duration:
'nz(whatever, 0) replaces nulls with 0
'# # hashtags delimit dates
Duration: Nz(DSum("Duration","WorkData","UserID = " & [UserID] & " AND StartDate = #" & [WorkDate] & "#"),0)
'sql
SELECT qryUsersWorkDates.UserName, qryUsersWorkDates.WorkDate, Nz(DSum("Duration","WorkData","UserID = " & [UserID] & " AND StartDate = #" & [WorkDate] & "#"),0) AS Duration
FROM qryUsersWorkDates;
'results
----------------------------------------------------------------
| UserName | WorkDate | Duration |
----------------------------------------------------------------
| User1 | 11/1/2021 | 1240 |
----------------------------------------------------------------
| User1 | 11/2/2021 | 0 |
----------------------------------------------------------------
| User2 | 11/1/2021 | 85 |
----------------------------------------------------------------
| User2 | 11/2/2021 | 0 |
----------------------------------------------------------------
You can copy the tables into text files and import them into Access. Sql can be copied into the sql pane of the query designer
You could use a subquery and a left join:
SELECT
[WorkData].User,
T.[Start Date],
Nz([Total], 0) As TotalDura
FROM
Calendar
LEFT JOIN
(Select User, [Start Date],
From WorkData
Group By User, [Start Date]
Having User = 'User1') As T
ON Calendar].Dates = T.[Sta
GROUP BY
[WorkData].User,
T.[Start Date],
Nz([Total], 0)
HAVING
[WorkData].User Is Not Null
Related
I'm trying to create a table to show the activy per session on a website.
Should look like something like that
Prefered table:
+------------+---------+--------------+-----------+
| SessionID | PageSeq| Page | Duration |
+------------+---------+--------------+-----------+
| 1 | 1 | Home | 5 |
| 1 | 2 | Sales | 10 |
| 1 | 3 | Contact | 9 |
| 2 | 1 | Sales | 5 |
| 3 | 1 | Home | 30 |
| 3 | 2 | Sales | 5 |
+------------+---------+--------------+-----------+
Unfortunetly my current dataset doesn't have information about the session_id, but can be deducted based on the time and the path.
Current table:
+------------------+---------+------------+---------------+----------+
| DATE_HOUR_MINUTE | Page | Prev_page | Total_session | Duration |
+------------------+---------+------------+---------------+----------+
| 201801012020 | Home | (entrance) | 24 | 5 |
| 201801012020 | Sales | Home | 24 | 10 |
| 201801012020 | Contact | Sales | 24 | 9 |
| 201801012020 | Sales | (entrance) | 5 | 5 |
| 201801012020 | Home | (entrance) | 35 | 30 |
| 201801012020 | Sales | Home | 35 | 5 |
+------------------+---------+------------+---------------+----------+
What is the best way to turn the current table into the prefered table format?
I've tried searching for nested tables, looped tables, haven't found a something related to this problem yet.
So if you can risk sessions starting at the same time with the same duration, should be easy enough to do using a recursive query.
;WITH sessionTree AS
(
SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) as sessionId
, 1 AS PageSeq
, *
FROM Session
WHERE PrevPage = '(entrance)'
UNION ALL
SELECT prev.sessionId
, prev.PageSeq + 1
, next.*
FROM sessionTree prev
JOIN Session next
ON next.TotalDuration = prev.TotalDuration
AND next.PrevPage = prev.Page
AND next.date_hour_minute >= prev.date_hour_minute
)
SELECT * FROM sessionTree
ORDER BY sessionId, PageSeq
sessionId is generated for each entry with (entrance) as prevPage, with PageSeq = 1. Then in the recursive part visits with the timestamp later than the previous page and with the same duration are joined on prev.page = next.PrevPage condition.
Here's a working example on dbfiddle
Hope you can help. We have a table with two columns Customer_ID and Trip_Date. The customer receives 15% off on their first visit and on every visit where they haven't received the 15% off offer in the past thirty days. How do I write a single SQL query that finds all days where a customer received 15% off?
The table looks like this
+-----+-------+----------+
| Customer_ID | date |
+-----+-------+----------+
| 1 | 01-01-17 |
| 1 | 01-17-17 |
| 1 | 02-04-17 |
| 1 | 03-01-17 |
| 1 | 03-15-17 |
| 1 | 04-29-17 |
| 1 | 05-18-17 |
+-----+-------+----------+
The desired output would look like this:
+-----+-------+----------+--------+----------+
| Customer_ID | date | received_discount |
+-----+-------+----------+--------+----------+
| 1 | 01-01-17 | 1 |
| 1 | 01-17-17 | 0 |
| 1 | 02-04-17 | 1 |
| 1 | 03-01-17 | 0 |
| 1 | 03-15-17 | 1 |
| 1 | 04-29-17 | 1 |
| 1 | 05-18-17 | 0 |
+-----+-------+----------+--------+----------+
We are doing this work in Netezza. I can't think of a way using just window functions, only using recursion and looping. Is there some clever trick that I'm missing?
Thanks in advance,
GF
You didn't tell us what your backend is, nor you gave some sample data and expected output nor you gave a sensible data schema :( This is an example based on guess of schema using postgreSQL as backend (would be too messy as a comment):
(I think you have Customer_Id, Trip_Date and LocationId in trips table?)
select * from trips t1
where not exists (
select * from trips t2
where t1.Customer_id = t2.Customer_id and
t1.Trip_Date > t2.Trip_Date
and t1.Trip_date - t2.Trip_Date < 30
);
I have a situation where I need to query from a 2 table in MS Access.
I'm new to this SQL access.
Table: UserInfo
===================
| UserID | Gender |
===================
| K01 | M |
| K02 | M |
| K03 | F |
| K04 | M |
===================
Table: OrderInfo
===================================
| OrderID | Type | UserID_FK |
===================================
| 1 | Food | K01 |
| 2 | Food | K01 |
| 3 | Toolkit | K02 |
| 4 | Food | K04 |
| 5 | Toolkit | K03 |
===================================
The question is:
I want to query so the result produce this table, how can I do it in MS Access?
I'm thinking that I should do a subquery but I don't know how to do it.
Table: Summary
================================================================
| UserID | Gender | CountOfToolkit | CountOfFood | TotalCount |
================================================================
| K01 | M | 0 | 2 | 2 |
| K02 | M | 1 | 0 | 1 |
| K03 | F | 1 | 0 | 1 |
| K04 | M | 0 | 1 | 1 |
================================================================
First, Type is a reserved word in MS Access.
You should avoid using reserved words.
Having said that, try this:
SELECT a.UserID, a.Gender, SUM(IIF(b.[Type] ='Food',1,0)) AS CountOfFood, SUM(IIF(b.[Type] ='Toolkit',1,0)) AS CountOfToolkit, COUNT(*) AS TotalCount
FROM UserInfo a INNER JOIN OrderInfo b ON a.UserId = b.UserID_FK
GROUP BY a.UserID, a.Gender
This crosstab query doesn't rely on having just Food & Toolkit as your types - it will count any new types you add.
The NZ wrapped around the Count(sType) ensures the 0 values are shown, while the CLNG ensures it's still treated as a number rather than text.
You could just use Count(sType) AS CountOfType.
TRANSFORM CLNG(NZ(Count(sType),0)) AS CountOfType
SELECT UserID
,Gender
,COUNT(sType) AS TotalCount
FROM UserInfo LEFT JOIN OrderInfo ON UserInfo.UserID = OrderInfo.UserID_FK
GROUP BY UserID, Gender
PIVOT sType
I have a table named tblOrders
| ID | name | email | amount | date |
+-----+---------+------------+---------+------------+
| 1 | danny | dan#email | $10.00 | 06/01/2015 |
| 2 | bryan | bra#email | $50.00 | 06/01/2015 |
| 3 | jenny | jen#email | $20.00 | 06/02/2015 |
| 4 | gabby | gab#email | $35.00 | 06/02/2015 |
| 5 | lisa | lisa#email | $12.00 | 06/03/2015 |
| 6 | don | don#email | $23.00 | 06/04/2015 |
| 7 | danny | dan#email | $22.00 | 06/04/2015 |
| 8 | bryan | bra#email | $55.00 | 06/05/2015 |
| 9 | danny | dan#email | $69.00 | 06/20/2015 |
| 10 | danny | dan#email | $49.00 | 06/25/2015 |
I want to select from tblOrders between date 06/03/2015 and 06/25/03/2015
and then count the number of repeated customers I have.
Select between date 06/03/2015 and 06/25/03/2015 provides
| ID | name | email | amount | date |
+----+-------+------------+--------+-------------+
| 5 | lisa | lisa#email | $12.00 | 06/03/2015 |
| 6 | don | don#email | $23.00 | 06/04/2015 |
| 7 | danny | dan#email | $22.00 | 06/04/2015 |
| 8 | bryan | bra#email | $55.00 | 06/05/2015 |
| 9 | danny | dan#email | $69.00 | 06/20/2015 |
| 10 | danny | dan#email | $49.00 | 06/25/2015 |
Then checking by email from those records if exist in all tblOrders and count
This should provide count of 2 as there are 2 customers between those dates that ordered before.
How can I achieve that with one SQL query?
I'm using Access database and ASP classic
My current code is
ReturnCustomers = 0
Set rs = Server.CreateObject("ADODB.Recordset")
SQL = ("select ID,Email,OrderDate from tblOrders Where OrderDate between #"&date1&"# and "&date2&";")
rs.Open SQL,Cnn,3,1
Do while Not rs.EOF
Set rsCount = Server.CreateObject("ADODB.Recordset")
SQL = ("select ID from tblOrders Where Email='"&rs("Email")&"' and Not ID="&rs("ID")&";")
rsCount.Open SQL,Cnn,3,1
IF Not rsCount.EOF Then
ReturnCustomers = ReturnCustomers+1
End IF
rsCount.Close
Set rsCount = Nothing
rs.MoveNext
Loop
rs.Close
Set rs = Nothing
response.write ReturnCustomers
How can I do this one in 1 SQL query?
It seems you want repeat customers --- those who made a purchase during the target date range and also made a purchase sometime before the start of that date range.
First create a query to retrieve those unique customers:
SELECT DISTINCT o1.email
FROM
tblOrders AS o1
INNER JOIN tblOrders AS o2
ON o1.email = o2.email
WHERE
(o1.date Between #2015-6-3# And #2015-6-25#)
AND o2.date < #2015-6-3#;
However you actually want only the count of those customers. So you can use the first query as a subquery and derive the count from that:
SELECT Count(sub.email) AS CountOfemail
FROM
(
SELECT DISTINCT o1.email
FROM
tblOrders AS o1
INNER JOIN tblOrders AS o2
ON o1.email = o2.email
WHERE
(o1.date Between #2015-6-3# And #2015-6-25#)
AND o2.date < #2015-6-3#
) AS sub;
you are not looking for duplicates. If you want to find out who ordered between date #06/03/2015# to #06/25/03/2015# and ordered before #06/03/2015# , your query should be like :
select distinct name, email from tblorders o
where date >=#06/03/2015# and date < #06/25/03/2015#
and exists (select * from tblorders p where p.email = o.email
and p.date <#06/03/2015# )
Also please specify your sql system.
Can you please help me build an SQL query to retrieve data from a history table?
I'm a newbie with only a one-week coding experience. I've been trying simple SELECT statements so far but have hit a stumbling block.
My football club's database has three tables. The first one links balls to players:
BallDetail
| BallID | PlayerID | TeamID |
|-------------------|--------|
| 1 | 11 | 21 |
| 2 | 12 | 22 |
The second one lists things that happen to the balls:
BallEventHistory
| BallID | Event | EventDate |
|--------|------ |------------|
| 1 | Pass | 2012-01-01 |
| 1 | Shoot | 2012-02-01 |
| 1 | Miss | 2012-03-01 |
| 2 | Pass | 2012-01-01 |
| 2 | Shoot | 2012-02-01 |
And the third one is a history change table. After a ball changes hands, history is recorded:
HistoryChanges
| BallID | ColumnName | ValueOld | ValueNew |
|--------|------------|----------|----------|
| 2 | PlayerID | 11 | 12 |
| 2 | TeamID | 21 | 22 |
I'm trying to obtain a table that would list all passes and shoots Player 11 had done to all balls before the balls went to other players. Like this:
| PlayerID | BallID | Event | Month |
|----------|--------|-------|-------|
| 11 | 1 | Pass | Jan |
| 11 | 1 | Shoot | Feb |
| 11 | 2 | Pass | Jan |
I begin so:
SELECT PlayerID, BallID, Event, DateName(month, EventDate)
FROM BallDetail bd INNER JOIN BallEventHistory beh ON bd.BallID = beh.BallID
WHERE PlayerID = 11 AND Event IN (Pass, Shoot) ...
But how to make sure that Ball 2 also gets included despite being with another player now?
Select PlayerID,BallID,Event,datename(month,EventDate) as Month,Count(*) as cnt from
(
Select
Coalesce(
(Select ValueNew from #HistoryChanges where ChangeDate=(Select max(ChangeDate) from #HistoryChanges h2 where h2.BallID=h.BallID and ColumnName='PlayerID' and ChangeDate<=EventDate) and BallID=h.BallID and ColumnName='PlayerID')
,(Select PlayerID from #BallDetail where BallID=h.BallID)
) as PlayerID,
h.BallID,h.Event,EventDate
from #BallEventHistory h
) a
Group by PlayerID, BallID, Event,datename(month,EventDate)
SELECT d.PlayerID, d.BallID, h.Event, DATENAME(mm, h.EventDate) AS Month
FROM BallDetail d JOIN BallEventHistory h ON d.BallID = h.BallID
WHERE h.Event IN ('Pass', 'Shoot') AND d.PlayerID = 11
OR EXISTS (SELECT 1
FROM dbo.HistoryChanges c
WHERE c.ValueOld = 11 AND c.ValueNew = d.PlayerID AND c.ColumnName = 'PlayerID' and c.ChangeDate = h.EventDate)