Recursive SQL command and duplicate results? - sql

I was wondering if how I am handling removing duplicate results using DISTINCT is the best way to approach my recursive call. Here is my code sample:
with cte as(
SELECT
dbo.Users.Username,
dbo.Contacts.FirstName,
dbo.Contacts.LastName,
tenant.Name,
tenant.Id,
tenant.ParentTenantId
FROM
dbo.Tenants AS tenant
INNER JOIN dbo.Users ON tenant.Id = dbo.Users.TenantId
INNER JOIN dbo.Contacts ON dbo.Users.ContactId = dbo.Contacts.Id
where tenant.Id = '6CD4C969-C794-4C95-9CA2-5984AEC0E32C'
union all
SELECT
dbo.Users.Username,
dbo.Contacts.FirstName,
dbo.Contacts.LastName,
childTenant.Name,
childTenant.Id,
childTenant.ParentTenantId
FROM
dbo.Tenants AS childTenant
INNER JOIN dbo.Users ON childTenant.Id = dbo.Users.TenantId
INNER JOIN dbo.Contacts ON dbo.Users.ContactId = dbo.Contacts.Id
INNER JOIN cte on childTenant.ParentTenantId = cte.Id)
select DISTINCT UserName, FirstName, LastName, Name, Id, ParentTenantId from cte ORDER BY Id
here are the results:
Here are the results without using the DISTINCT key word
While DISTINCT works I am wondering if it is the best way to handle the duplicate results or if I should rework my query somehow.

I'm not sure whether that is the case here, but it is a common misunderstanding that distinct is a function that applies to a certain column. Distinct applies to the row, that is:
select distinct(x), y from t
is the same as:
select distinct x, y from t or select distinct x, (y) from t
Furthermore:
select x, distinct(y) from t
is an invalid construction

Related

Remove duplicates from result in sql

i have following sql in java project:
select distinct * from drivers inner join licenses on drivers.user_id=licenses.issuer_id
inner join users on drivers.user_id=users.id
where (licenses.state='ISSUED' or drivers.status='WAITING')
and users.is_deleted=false
And result i database looks like this:
And i would like to get only one result instead of two duplicated results.
How can i do that?
Solution 1 - That's Because one of data has duplicate value write distinct keyword with only column you want like this
Select distinct id, distinct creation_date, distinct modification_date from
YourTable
Solution 2 - apply distinct only on ID and once you get id you can get all data using in query
select * from yourtable where id in (select distinct id from drivers inner join
licenses
on drivers.user_id=licenses.issuer_id
inner join users on drivers.user_id=users.id
where (licenses.state='ISSUED' or drivers.status='WAITING')
and users.is_deleted=false )
Enum fields name on select, using COALESCE for fields which value is null.
usually you dont query distinct with * (all columns), because it means if one column has the same value but the rest isn't, it will be treated as a different rows. so you have to distinct only the column you want to, then get the data
I suspect that you want left joins like this:
select *
from users u left join
drivers d
on d.user_id = u.id and d.status = 'WAITING' left join
licenses l
on d.user_id = l.issuer_id and l.state = 'ISSUED'
where u.is_deleted = false and
(d.user_id is not null or l.issuer_id is not null);

SUM a column count from two tables

I have this simple unioned query in SQL Server 2014 where I am getting counts of rows from each table, and then trying to add a TOTAL row at the bottom that will SUM the counts from both tables. I believe the problem is the LEFT OUTER JOIN on the last union seems to be only summing the totals from the first table
SELECT A.TEST_CODE, B.DIVISION, COUNT(*)
FROM ALL_USERS B, SIGMA_TEST A
WHERE B.DOMID = A.DOMID
GROUP BY A.TEST_CODE, B.DIVISION
UNION
SELECT E.TEST_CODE, F.DIVISION, COUNT(*)
FROM BETA_TEST E, ALL_USERS F
WHERE E.DOMID = F.DOMID
GROUP BY E.TEST_CODE, F.DIVISION
UNION
SELECT 'TOTAL', '', COUNT(*)
FROM (SIGMA_TEST A LEFT OUTER JOIN BETA_TEST E ON A.DOMID
= E.DOMID )
Here is a sample of the results I am getting:
I would expect the TOTAL row to display a result of 6 (2+1+3=6)
I would like to avoid using a Common Table Expression (CTE) if possible. Thanks in advance!
Since you are counting users with matching DOMIDs in the first two statements, the final statement also needs to include the ALL_USERS table. The final statement should be:
SELECT 'TOTAL', '', COUNT(*)
FROM ALL_USERS G LEFT OUTER JOIN
SIGMA_TEST H ON G.DOMID = H.DOMID
LEFT OUTER JOIN BETA_TEST I ON I.DOMID = G.DOMID
WHERE (H.TEST_CODE IS NOT NULL OR I.TEST_CODE IS NOT NULL)
I would consider doing a UNION ALL first then COUNT:
SELECT COALESCE(TEST_CODE, 'TOTAL'),
DIVISION,
COUNT(*)
FROM (
SELECT A.TEST_CODE, B.DIVISION
FROM ALL_USERS B
INNER JOIN SIGMA_TEST A ON B.DOMID = A.DOMID
UNION ALL
SELECT E.TEST_CODE, F.DIVISION
FROM BETA_TEST E
INNER JOIN ALL_USERS F ON E.DOMID = F.DOMID ) AS T
GROUP BY GROUPING SETS ((TEST_CODE, DIVISION ), ())
Using GROUPING SETS you can easily get the total, so there is no need to add a third subquery.
Note: I assume you want just one count per (TEST_CODE, DIVISION). Otherwise you have to also group on the source table as well, as in #Gareth's answer.
I think you can achieve this with a single query. It seems your test tables have similar structures, so you can union them together and join to ALL_USERS, finally, you can use GROUPING SETS to get the total
SELECT ISNULL(T.TEST_CODE, 'TOTAL') AS TEST_CODE,
ISNULL(U.DIVISION, '') AS DIVISION,
COUNT(*)
FROM ALL_USERS AS U
INNER JOIN
( SELECT DOMID, TEST_CODE, 'SIGNMA' AS SOURCETABLE
FROM SIGMA_TEST
UNION ALL
SELECT DOMID, TEST_CODE, 'BETA' AS SOURCETABLE
FROM BETA_TEST
) AS T
ON T.DOMID = U.DOMID
GROUP BY GROUPING SETS ((T.TEST_CODE, U.DIVISION, T.SOURCETABLE), ());
As an aside, the implicit join syntax you are using was replaced over a quarter of a century ago in ANSI 92. It is not wrong, but there seems to be little reason to continue to use it, especially when you are mixing and matching with explicit outer joins and implicit inner joins. Anyone else that might read your SQL will certainly appreciate consistency.

SQL Server Join on Select statement using count() and group by

I have two tables in SQL Server, tbl_disputes and tbl_disputetypes. The tbl_disputes table contains a foreign key column disputetype. The table tbl_disputetypes contains the primary key field disputetypeid and disputetypedesc. The following query gives me a count of each disputetype from the tbl_disputes table.
select disputetype, count(disputetype) as numberof
from tbl_disputes
group by disputetype
What sort of join or subquery do I need to use to display the
tbl_disputetypes.dbo.disputetypedesc instead of tbl_disputes.dbo.disputetype?
EDIT Issue was because disputetypedesc was set as TEXT. I changed it to nvarchar, and the following query worked:
SELECT
tbl_disputetypes.disputetypedesc,
count(tbl_disputetypes.disputetypedesc)
FROM
tbl_disputes Left OUTER JOIN
tbl_disputetypes ON tbl_disputes.disputetype = tbl_disputetypes.disputetypeid
group by tbl_disputetypes.disputetypedesc
Unless I'm missing something, you can just LEFT JOIN the description:
select disputetypedesc, count(disputetype) as numberof
from tbl_disputes d
LEFT JOIN tbl_disputetypes dt
ON dt.disputetypeid = d.disputetype
group by disputetypedesc
Assuming 2005+:
WITH x(t, numberof) AS
(
SELECT disputetype, COUNT(*)
FROM tbl_disputes
GROUP BY disputetype
)
SELECT dt.disputetypedesc, x.numberof
FROM tbl_disputetypes AS dt
INNER JOIN x ON dt.disputetype = x.t;
A simple JOIN?
select
DT.disputetypedesc, count(*) as numberof
from
tbl_disputes D
JOIN
tbl_disputetypes DT ON D.disputetype = DT.disputetype
group by
DT.disputetypedesc
The basic idea is that you will need a sub-query. Something like this will work:
select disputetypedesc, disputetype, numberof
from (select disputetype, count(disputetype) numberof
from tbl_disputes
group by disputetype) t left outer join
tbl_disputetypes on t.disputetype = tbl_disputetypes.disputetype
I am not sure if I understand your question however you should be able to select all columns using a query similar to the code sample below.
The following query will join the two tables by the disputetypeid column. I changed the format of the SQL statement however you can obviously format it however you would like.
SELECT tbl_disputetypes.disputetypedesc
, tbl_disputes.*
, <any_column_from_either_table>
FROM tbl_disputes
INNER JOIN tbl_disputetypes
ON tbl_disputes.disputetypeid = tbl_disputetypes.disputetypeid

Oracle SQL help

I posted on Friday (sql multiple count) and had a few responses.
Having tried to implement them today, I keep getting the same error.
My SQL code now is:
SELECT MBDDX_STUDY.STUDY_NAME,
COUNT(MBDDX_EXPERIMENT.STUDY_ID)
AS NUMBER_OF_EXPERIMENTS
FROM MBDDX_STUDY
INNER JOIN MBDDX_EXPERIMENT
ON MBDDX_STUDY.ID = MBDDX_EXPERIMENT.STUDY_ID
INNER JOIN (SELECT COUNT(MBDDX_TREATMENT_GROUP.GROUP_NO)
FROM MBDDX_TREATMENT_GROUP)
ON MBDDX_TREATMENT_GROUP.STUDY_ID = MBDDX_STUDY.ID
GROUP BY MBDDX_STUDY.STUDY_NAME
I keep getting the error:
ORA-00904: "MBDDX_TREATMENT_GROUP"."STUDY_ID": invalid identifier
Is it because it is outside of the inner join bracket, i.e. out of scope? I am very new to SQL and cannot understand why it wont work. I can get it working using select subqueries (without joins) but I want to also be able to work with joins.
If it matters any I am using Toad for Oracle.
Thanks.
Because you join with a query. Give a name to that query, and refer to it that way:
SELECT MBDDX_STUDY.STUDY_NAME
, COUNT ( MBDDX_EXPERIMENT.STUDY_ID )
AS NUMBER_OF_EXPERIMENTS
FROM MBDDX_STUDY
INNER JOIN MBDDX_EXPERIMENT
ON MBDDX_STUDY.ID = MBDDX_EXPERIMENT.STUDY_ID
inner JOIN ( SELECT study_id, COUNT ( MBDDX_TREATMENT_GROUP.GROUP_NO )
FROM MBDDX_TREATMENT_GROUP group by study_id ) AS my_query
ON my_query.STUDY_ID = MBDDX_STUDY.ID
GROUP BY MBDDX_STUDY.STUDY_NAME
For one thing, a subquery must have an alias. Change:
inner JOIN ( SELECT COUNT ( MBDDX_TREATMENT_GROUP.GROUP_NO )
FROM MBDDX_TREATMENT_GROUP )
ON MBDDX_TREATMENT_GROUP.STUDY_ID = MBDDX_STUDY.ID
to
inner JOIN ( SELECT COUNT ( MBDDX_TREATMENT_GROUP.GROUP_NO )
FROM MBDDX_TREATMENT_GROUP ) as CountAlias
ON MBDDX_TREATMENT_GROUP.STUDY_ID = MBDDX_STUDY.ID
The second thing is that you have to include all columns you plan to use. Right now, the subquery just selects a count, but the ON clause references STUDY_ID. You can fix that by including STUDY_ID in the subquery select list, like:
inner JOIN (
SELECT STUDY_ID
, COUNT(MBDDX_TREATMENT_GROUP.GROUP_NO) as GroupCount
FROM MBDDX_TREATMENT_GROUP) as CountAlias
ON MBDDX_TREATMENT_GROUP.STUDY_ID = MBDDX_STUDY.ID
Now after that, you might hit other issues, but I'm hoping this will get you started.

MS-SQL problem - Only one expression can be specified in the select list

I write the following query:
select
id,
(select NameEn from [Campaign] where id=CampaignId) as CampaignName,
createdDate,
(select Name, IdNo, Email, MobileNo from [Members] where id=MemberId)
from
Transactions
and error occurs:
"Only one expression can be specified in the select list when the subquery is not introduced with EXISTS."
How can I rewrite the SQL to make it correct?
You need to use proper (inner|left|...) join syntax.
Something like:
select
t.id,
c.NameEn,
t.createdDate,
m.Name,
m.IdNo,
m.Email,
m.MobileNo
from
[Transactions] t
inner join [Campaign] c on c.id = t.CampaignId
inner join [Members] m on m.id = t.MemberId
Also, in your original code, one of
select NameEn from [Campaign] where id=CampaignId
or
select Name,IdNo,Email,MobileNo from [Members] where id=MemberId
might be returning more than one row for each row of [Transactions], which would be illegal.