How to count unique events in Access? - sql

I am trying to count the unique number of events in the E_CUSTOMER_DETAIL_1.E_CUST_LOGIN_ID field using count(distinct(E_CUSTOMER_DETAIL_1.E_CUST_LOGIN_ID)), but I get an error when performing the following query in MS Access 2016.
How to count unique events in the E_CUSTOMER_DETAIL_1.E_CUST_LOGIN_ID field?
My query in MS Access 2016 (without distinct):
SELECT CUSTOMERS.E_CUST_LOGIN_ID, Count(E_CUSTOMER_DETAIL_1.E_CUST_LOGIN_ID)
FROM ((((CUSTOMERS
INNER JOIN E_CUSTOMER_DETAIL ON CUSTOMERS.WH_CUST_NO = E_CUSTOMER_DETAIL.WH_CUST_NO)
INNER JOIN E_CUST_E_CUST_REL ON CUSTOMERS.E_CUST_LOGIN_ID = E_CUST_E_CUST_REL.E_CUST_LOGIN_ID)
INNER JOIN E_CUST_CHNL_USAGE_DETAIL ON E_CUST_E_CUST_REL.E_CUST_JOINT_OWN_LOGIN_ID = E_CUST_CHNL_USAGE_DETAIL.E_CUST_LOGIN_ID)
INNER JOIN E_CUSTOMER_DETAIL AS E_CUSTOMER_DETAIL_1 ON E_CUST_E_CUST_REL.E_CUST_JOINT_OWN_LOGIN_ID = E_CUSTOMER_DETAIL_1.E_CUST_LOGIN_ID)
GROUP BY CUSTOMERS.E_CUST_LOGIN_ID;

MS Access does not support count(distinct). One way to work around this limitation is to select distinct in a subquery, then aggregate:
SELECT LOGIN_ID, Count(DETAIL_LOGIN_ID)
FROM (
SELECT DISTINCT CUSTOMERS.E_CUST_LOGIN_ID AS LOGIN_ID, E_CUSTOMER_DETAIL_1.E_CUST_LOGIN_ID AS DETAIL_LOGIN_ID
FROM ((((CUSTOMERS
INNER JOIN E_CUSTOMER_DETAIL ON CUSTOMERS.WH_CUST_NO = E_CUSTOMER_DETAIL.WH_CUST_NO)
INNER JOIN E_CUST_E_CUST_REL ON CUSTOMERS.E_CUST_LOGIN_ID = E_CUST_E_CUST_REL.E_CUST_LOGIN_ID)
INNER JOIN E_CUST_CHNL_USAGE_DETAIL ON E_CUST_E_CUST_REL.E_CUST_JOINT_OWN_LOGIN_ID = E_CUST_CHNL_USAGE_DETAIL.E_CUST_LOGIN_ID)
INNER JOIN E_CUSTOMER_DETAIL AS E_CUSTOMER_DETAIL_1 ON E_CUST_E_CUST_REL.E_CUST_JOINT_OWN_LOGIN_ID = E_CUSTOMER_DETAIL_1.E_CUST_LOGIN_ID)
)
GROUP BY LOGIN_ID;

Related

Joining a Query and sub-query

I'm trying to join a query and a sub-query in Access but haven't the faintest idea on how to do that. Rather than saving the sub-query as a different query and then joining it to the main query.
Main query (with reference to sub-query):
SELECT tb200_IraDataIn.tb200_niarnum, tb206_IraAccount.tb206_IraAccDesc,
tb206_IraAccount.tb206_IraAccNum, tb15_Securities.tb15_IsActiveRegister,
tb15_Securities.tb15_NiarDesc, tb15_Securities.tb15_ManpikID, tb200_IraDataIn.tb200_Shovi, tb10_Afik.tb10_InvestTool,
tb206_IraAccount.tb206_IsActive, tb200_IraDataIn.tb200_Shovi,
tb200_IraDataIn.tb200_Shovi/SubQuery1.SumOftb200_Shovi AS Expr1
FROM SubQuery1
INNER JOIN (tb10_Afik
INNER JOIN (tb15_Securities
INNER JOIN (tb206_IraAccount
INNER JOIN tb200_IraDataIn
ON tb206_IraAccount.tb206_IraAccNum = tb200_IraDataIn.tb200_accountNumber)
ON tb15_Securities.tb15_NiarID = tb200_IraDataIn.tb200_niarnum)
ON (tb10_Afik.tb10_AfikID = tb200_IraDataIn.tb200_afik) AND (tb10_Afik.tb10_Erp =tb200_IraDataIn.tb200_ERP))
ON SubQuery1.tb206_IraAccNum = tb206_IraAccount.tb206_IraAccNum
WHERE (((tb15_Securities.tb15_IsActiveRegister)=Yes) AND ((tb10_Afik.tb10_InvestTool)=1
Or (tb10_Afik.tb10_InvestTool)=4 Or (tb10_Afik.tb10_InvestTool)=21 Or
(tb10_Afik.tb10_InvestTool)=3) AND ((tb206_IraAccount.tb206_IsActive)=Yes) AND
(([tb200_IraDataIn].[tb200_Shovi]/[SubQuery1].[SumOftb200_Shovi])>0.1));
subquery (saved as SubQuery1):
SELECT tb206_IraAccount.tb206_IraAccDesc, tb206_IraAccount.tb206_IraAccNum, Sum(tb200_IraDataIn.tb200_Shovi) AS SumOftb200_Shovi
FROM tb206_IraAccount
INNER JOIN tb200_IraDataIn ON tb206_IraAccount.tb206_IraAccNum = tb200_IraDataIn.tb200_accountNumber
WHERE (((tb206_IraAccount.tb206_IsActive)=Yes))
GROUP BY tb206_IraAccount.tb206_IraAccDesc, tb206_IraAccount.tb206_IraAccNum;
How can I put the sql statement of the sub-query inside the same Sql statement of the main query, unlike now?
Thanks!
Nest between parentheses. Nothing else in the main query changes.
SELECT
...
FROM (SELECT tb206_IraAccount.tb206_IraAccDesc, tb206_IraAccount.tb206_IraAccNum, Sum(tb200_IraDataIn.tb200_Shovi) AS SumOftb200_Shovi
FROM tb206_IraAccount
INNER JOIN tb200_IraDataIn ON tb206_IraAccount.tb206_IraAccNum = tb200_IraDataIn.tb200_accountNumber
WHERE (((tb206_IraAccount.tb206_IsActive)=Yes))
GROUP BY tb206_IraAccount.tb206_IraAccDesc, tb206_IraAccount.tb206_IraAccNum) AS SubQuery1
...

How to Distinct a sql query but still return all columns

This is my query:
SELECT dbo.Webs.Id, dbo.Webs.Title, dbo.Webs.FullUrl, dbo.Roles.RoleId,
dbo.Roles.Title AS RoleTitle, dbo.UserInfo.tp_Title, dbo.UserInfo.tp_Login
FROM dbo.RoleAssignment
INNER JOIN dbo.Roles ON dbo.RoleAssignment.SiteId = dbo.Roles.SiteId
AND dbo.RoleAssignment.RoleId = dbo.Roles.RoleId
INNER JOIN dbo.Webs ON dbo.Roles.SiteId = dbo.Webs.SiteId
AND dbo.Roles.WebId = dbo.Webs.Id
INNER JOIN dbo.UserInfo ON dbo.RoleAssignment.PrincipalId = dbo.UserInfo.tp_ID
WHERE tp_Title = 'HOBSON, Will';
This database contains all the permissions for the users of all sharepoint sites. I'm trying to create a query that displays all sites the user has access to. Currently it outputs a lot of duplicate information. I only want it to display results that have either a distinct Role Title or a distinct Web id.
So for example, in this query I would only want to see 4 results; 1, 5, 11 and 13.
(all this information is on a local test SharePoint installation that cannot be accessed externally, so the only information I'm giving away here is my name :))
Your query would be much easier to read with table aliases. The direct answer to your question is to use SELECT DISTINCT:
SELECT DISTINCT w.Id, w.Title, w.FullUrl, r.RoleId, r.Title AS RoleTitle,
ui.tp_Title, ui.tp_Login
FROM dbo.RoleAssignment ra INNER JOIN
dbo.Roles r
ON ra.SiteId = r.SiteId AND
ra.RoleId = r.RoleId INNER JOIN
dbo.Webs w
ON r.SiteId = w.SiteId AND
r.WebId = w.Id INNER JOIN
dbo.UserInfo ui
ON ra.PrincipalId = ui.tp_ID
WHERE tp_Title = 'HOBSON, Will';
However, it would be better to find the cause of the duplicates. Often duplicates like this are caused by incomplete join conditions. Fixing the join is the better approach, but sometimes SELECT DISTINCT is necessary.
You can just add a DISTINCT to your query:
SELECT DISTINCT dbo.Webs.Id, dbo.Webs.Title, dbo.Webs.FullUrl, dbo.Roles.RoleId,
dbo.Roles.Title AS RoleTitle, dbo.UserInfo.tp_Title, dbo.UserInfo.tp_Login
FROM dbo.RoleAssignment
INNER JOIN dbo.Roles ON dbo.RoleAssignment.SiteId = dbo.Roles.SiteId
AND dbo.RoleAssignment.RoleId = dbo.Roles.RoleId
INNER JOIN dbo.Webs ON dbo.Roles.SiteId = dbo.Webs.SiteId
AND dbo.Roles.WebId = dbo.Webs.Id
INNER JOIN dbo.UserInfo ON dbo.RoleAssignment.PrincipalId = dbo.UserInfo.tp_ID
WHERE tp_Title = 'HOBSON, Will';

SQL Selecting rows with not the same condition for all

I have to create SQL query that select persons datas. Every person has several grades and I have to select first by time for everyone. I don't know how do it because conditional is different for every person. Below is my current code which doesn't works.
SELECT s.sol_last_name,
g.grade_name,
MIN(sg.sol_grade_date_from)
FROM [dbo].[dim_s####] AS s
LEFT JOIN [dbo].[fact_s####_grade] AS sg ON s.sol_key = sg.sol_grade_sollers_key
LEFT JOIN [dbo].[dim_grade] AS g ON g.grade_key = sg.sol_grade_grade_key
GROUP BY s.sol_last_name,
g.grade_name
HAVING MIN(sg.sol_grade_date_from) = sg.sol_grade_date_from
You can put the earliest date in a subquery, and then inner join there:
SELECT s.sol_last_name,
g.grade_name,
sg.sol_grade_date_from
FROM [dbo].[dim_s####] AS s
INNER JOIN (
select sol_grade_grade_key
,min(sol_grade_date_from) as sol_grade_date_
from from [dbo].[dim_grade]
GROUP BY sol_grade_grade_key) AS g
ON g.grade_key = sg.sol_grade_grade_key
LEFT JOIN [dbo].[fact_s####_grade] AS sg
ON s.sol_key = sg.sol_grade_sollers_key
Use a Common Table Expression (cte) to save some typing. Then do a NOT EXISTS to return a row only if same sol_last_name has no older grade.
WITH CTE (sol_last_name, grade_name, grade_date_from) AS
(
SELECT s.sol_last_name,
g.grade_name,
sg.sol_grade_date_from
FROM [dbo].[dim_s####] AS s
LEFT JOIN [dbo].[fact_s####_grade] AS sg ON s.sol_key = sg.sol_grade_sollers_key
LEFT JOIN [dbo].[dim_grade] AS g ON g.grade_key = sg.sol_grade_grade_key
)
select sol_last_name, grade_name, grade_date_from
from cte as t1
where not exists (select 1 from cte t2
where t2.sol_last_name = t1.sol_last_name
and t2.grade_date_from < t2.grade_date_from)

Using MAX function in a subquery in Access

In Microsoft Access, I'm querying data from four tables and I'm using the MAX function to display the most recent records. The code below works but it's using two queries linked together. By using a sub-query, shown below with the full code, the code takes an hour to run, which is why I using two queries. Is there a better way of doing this?
QUERY 1
SELECT
a.office_id AS ofid,
rc.recorder_id AS recorder,
a.cust_name,
r.account_id,
rc.lpc_phone,
rc.device_serial,
rc.device_mfg,
rc.device_type
INTO RDS_INFO
FROM MaxDates
INNER JOIN (status AS s INNER JOIN ((config_recorder AS rc INNER JOIN recorders AS r ON rc.recorder_id = r.recorder_id)
INNER JOIN accounts AS a ON r.account_id = a.account_id) ON s.status = rc.row_status) ON (MaxDates.MaxOftrans_datetime = rc.trans_datetime) AND (MaxDates.recorder_id = rc.recorder_id)
WHERE (((rc.lpc_phone) Is Not Null
And (rc.lpc_phone)<>" "
And (rc.lpc_phone) Not Like "#,*")
AND ((rc.call_mode)="AN")
AND ((rc.row_status)=3
Or (rc.row_status)=11));
MaxDates Query:
SELECT
config_recorder.recorder_id,
Max(config_recorder.trans_datetime) AS MaxOftrans_datetime
FROM config_recorder
GROUP BY config_recorder.recorder_id;
Code used with the sub-query:
SELECT
a.cycle AS cyc,
a.office_id AS ofid,
rc.recorder_id AS recorder,
a.cust_name,
r.account_id,
rc.lpc_phone,
rc.device_serial,
rc.device_mfg,
rc.device_type
INTO Test
FROM config_recorder AS rc, status AS s, recorders AS r, accounts AS a
WHERE rc.recorder_id=r.recorder_id
AND r.account_id=a.account_id
AND ((rc.lpc_phone Is Not Null)
AND (rc.lpc_phone<>" ")
AND (rc.lpc_phone Not Like "#,*"))
AND ((rc.call_mode="AN")
AND (rc.row_status=s.status)
AND ((rc.row_status="3")
Or (rc.row_status="11")))
AND (rc.trans_datetime=(select max(r2.trans_datetime) from config_recorder r2 where r2.recorder_id = rc.recorder_id));
Thank you for your help.
You can consider changing the sub-query into an inline view and then joining it with other tables, as below:
SELECT
a.office_id AS ofid,
rc.recorder_id AS recorder,
a.cust_name,
r.account_id,
rc.lpc_phone,
rc.device_serial,
rc.device_mfg,
rc.device_type
INTO RDS_INFO
FROM status AS s
INNER JOIN
(config_recorder AS rc INNER JOIN recorders AS r ON rc.recorder_id = r.recorder_id)
ON s.status = rc.row_status
INNER JOIN accounts AS a
ON r.account_id = a.account_id
INNER JOIN
(SELECT
config_recorder.recorder_id,
Max(config_recorder.trans_datetime) AS MaxOftrans_datetime
FROM config_recorder
GROUP BY config_recorder.recorder_id) MaxDates
ON (MaxDates.MaxOftrans_datetime = rc.trans_datetime) AND (MaxDates.recorder_id = rc.recorder_id)
WHERE (((rc.lpc_phone) Is Not Null
And (rc.lpc_phone)<>" "
And (rc.lpc_phone) Not Like "#,*")
AND ((rc.call_mode)="AN")
AND ((rc.row_status)=3
Or (rc.row_status)=11));
References:
A related question on SO
Inline Views Versus Temp Tables on MSDN Magazine

SQL Join only if all records have a match

I have 3 tables:
CP_carthead (idOrder)
CP_cartrows (idOrder, idCartRow)
CP_shipping (idCartRow, idShipping, dateShipped)
There can be multiple idCartRows per idOrder.
I want to get all orders where all its idCartRows exist in CP_shipping. This seems like it should be simple, but I haven't found much on the web.
Here's my query now:
SELECT
s.idOrder
, s.LatestDateShipped
FROM
CP_carthead o
LEFT OUTER JOIN (
SELECT
MAX(s.dateShipped) [LatestDateShipped]
, r.idOrder
FROM
CP_shipping s
LEFT OUTER JOIN CP_cartrows r ON s.idCartRow = r.idCartRow
GROUP BY
r.idOrder
) s ON o.idOrder = s.idOrder
Your query is returning rows from "s" and not the orders. Based on your question, I came up with this query:
select o.*
from CP_Carthead o
where o.orderId in (select cr.idOrder
from cp_cartrows cr left outer join
cp_shipping s
on cr.idCartRow = s.IdCartrow
group by cr.idOrder
having count(s.idCartRow) = COUNT(*)
)
The subquery in the in statement is getting orders all of whose cartrows are in shipping.