How to write the sql statement for the below query? - sql

i have a table(lab_schedule) columns as below,
c_code labclass day
EEI4163 2019-04-09 Sunday
EEI4362 2019-03-05 Monday
EEI4362 2019-04-07 Tuesday
EEI4456 2019-05-06 Wednesday
I want view the course codes which do not have lab class on 2019-03-05
select c_Code,labclass
from lab_schedule
where labclass != "2019-03-05" group by c_code,labclass;
i tried to get the result by using the group by syntax in sql. but I expected only EEI4163, EEI4456 but it shows EEI4362 too which is in 2019-04-07.
But EEI4362 course has a lab class on 2019-03-05.

One method uses aggregation:
select c_Code
from lab_schedule
group by c_code
having sum(case when labclass = '2019-03-05' then 1 else 0 end) = 0

You can use a self-outer join as an alternative solution like below:
select l1.c_Code, l1.labclass
from lab_schedule l1
left outer join lab_schedule l2 on l1.c_Code = l2.c_Code and l2.labclass = '2019-03-05'
where l2.c_Code is null
group by l1.c_Code, l1.labclass
Edit: If you wanna see only c_code, remove l1.labclass from "select" and "group by" statements.

Your code removes the rows where labclass = "2019-03-05" but if a course code has lab class on "2019-03-07" and in another date it will still be in the results with the row with the other date.
Use NOT EXISTS:
select s.c_Code, s.labclass, s.day
from lab_schedule s
where not exists (
select 1 from lab_schedule
where c_Code = s.c_Code and labclass = "2019-03-05"
)
If you want only the c_Code column
select distinct s.c_Code
from lab_schedule s
where not exists (
select 1 from lab_schedule
where c_Code = s.c_Code and labclass = "2019-03-05"
)
See the demo.
Results:

Related

Find NON-duplicate column value combinations

This is for a migration script.
CompanyTable:
EmployeeId
DivisionId
abc
div1
def
div1
abc
div1
abc
div2
xyz
div2
In the below code I am Selecting duplicate EmployeeId-DivisionId combinations, that is, the records that have the same EmployeeId and DivisionId will be selected. So from the above table, the two rows that have abc-div1 combination will be selected by the below code.
How can I invert it? It seems so simple but I can't figure it out. I tried replacing with HAVING count(*) = 0 instead of > 1, I've tried fiddling with the equality signs in the ON and AND lines. Basically from the above table, I want to select the other three rows that don't have the abc-div1 combination. If there is a way to select all the unique EmployeeID-DivisionId combinations, let me know.
SELECT a.EmployeeID, a.DivisionId FROM CompanyTable a
JOIN ( SELECT EmployeeID, DivisionId
FROM CompanyTable
GROUP BY EmployeeID, DivisionId
HAVING count(*) > 1 ) b
ON a.EmployeeID = b.EmployeeID
AND a.DivisionId = b.DivisionId;
EmployeeId and DivisionId are both nvarchar(50) columns.
A windowed count would seem a suitable method:
select employeeid, divisionid
from (
select *, Count(*) over(partition by employeeid, divisionid) ct
from t
)t
where ct = 1;
As already mentioned, you must replace > 1 by its real opposite <= 1, this works: db<>fiddle
First, let's try rewriting your query using a common table expression (CTE), instead of a subquery:
WITH cteCompanyTableStats as (
SELECT
EmployeeID, DivisionId,
HasDuplicates = CASE WHEN count(*) > 1 THEN1 ELSE 0 END
FROM CompanyTable
GROUP BY EmployeeID, DivisionId
)
SELECT ct.*
FROM CompanyTable ct
inner join cteCompanyTableStats cts on
ct.EmployeeId = cts.EmployeeId
and ct.DivisionId = cts.DivisionId
and cts.HasDuplicates = 1
Notice how I've removed the HAVING clause & added a new HasDuplicates column? We're going to use that new column to find all of the table rows that -DON'T- have duplicates:
WITH cteCompanyTableStats as (
SELECT
EmployeeID, DivisionId,
HasDuplicates = CASE WHEN count(*) > 1 THEN1 ELSE 0 END
FROM CompanyTable
GROUP BY EmployeeID, DivisionId
)
SELECT ct.*
FROM CompanyTable ct
inner join cteCompanyTableStats cts on
ct.EmployeeId = cts.EmployeeId
and ct.DivisionId = cts.DivisionId
and cts.HasDuplicates = 0
The only character of SQL code that changed between the two queries was the last line, where and cts.HasDuplicates = ### is set.

Use sql variables in query results

I have some of the following code:
Select p.CLIENT_NO,
s.CLIENT_NAME,
s.CLIENT_TYPE,
p.GL_CODE,
p.BATCH_KEY
From RU_POST p,
RU_ACCT a,
Ru_Ru s
Where
a.INTERNAL_KEY(+) = p.INTERNAL_KEY
And p.Batch_Key in
(Select Distinct (p1.BATCH_KEY)
From RU_POST p1
Where Abs(p1.AMOUNT) <> 0
And p1.POST_DATE Between To_Date('01-01-2015', 'dd-mm-yyyy') And
To_Date('01-01-2015', 'dd-mm-yyyy')
And p1.INTERNAL_KEY In ('367', '356'))
Now I want to have values stated in p1.INTERNAL_KEY to appear in query results, like if I did SELECT p1.INTERNAL_KEY.
However, I understand this won't work. So, it would be like '367' for 100 values, '356' for other 100.
Could someone help me how to put this condition value inside my result?
Like that:
CLIENT_NO CLIENT_SHORT CLIENT_NAME GL_CODE INTERNAL_KEY
399999000 399999 A 4568 367
599999000 599999 B 4879 356
You can try changing the in subquery to a join, like this:
select distinct
p.client_no
, s.client_name
, s.client_type
, p.gl_code
, p1.internal_key
from ru_post p
join ru_post p1 on p1.batch_key = p.batch_key
left join ru_acct a on a.internal_key = p.internal_key
cross join ru_ru s
where abs(p1.amount) <> 0
and p1.post_date between date '2015-01-01' and date '2015-01-01'
and p1.internal_key in ('367', '356') );
(Edited to match updated question - now left join ru_post to ru_acct):

SQL count DISTINCT ONCE user_id multiple attributes

Hello there I cant manage to get a good result for the following case:
I have a table which is like this:
UserID | Label
-------- ------
1 | Private
1 | Public
2 | Private
3 | Hidden
4 | Public
5 | Hidden
I want to have the following happening if a User has following assigned he is:
Private and Hidden are treaten the same: lets say Business
Public: BtoC
Public and Private and/or Hidden: both
So in the end I have a count(DISTINCT UserID) of
Business 3
BtoC 1
both 1
I have tried to use CASE WHEN but it doesn't work my current total query looks like this:
SELECT gen_month,
count(DISTINCT cu.id) as leads,
a.label
FROM generate_series(DATE_TRUNC('month', CURRENT_DATE::date - 96*INTERVAL '1 month'), CURRENT_DATE::date, '1 month') m(gen_month)
LEFT OUTER JOIN company_user AS cu
ON (date_trunc('month', cu.creation_date) = date_trunc('month', gen_month))
LEFT JOIN user u
ON u.user_id = cu.id
LEFT join user_account_status as uas
on cu.id = uas.user_id
LEFT JOIN account as a
on uas.account_id = a.id
where gen_month >= DATE_TRUNC('month',NOW() - INTERVAL '5 months')
group by m.gen_month, a.label
order by gen_month
So my main problem now is that the count appears in every attribute once.
How can I make a userid only count once under condition CASE WHEN user_id appears Public and (Private or Hidden) THEN count(DISTINCT user_id) as Both?
Addition: its mySQL mariaDB and postgreSQL. But first I would happy with Postgres
This is not implemented in your total query, but for counting users for each category, you can:
with the_table(UserID , Label) as(
select 1 ,'Private' union all
select 1 ,'Public' union all
select 2 ,'Private' union all
select 3 ,'Hidden' union all
select 4 ,'Public' union all
select 5 ,'Hidden'
)
select result, count(*) from (
select UserID, case when min(Label) = 'Public' then 'BtoC' when max(Label) in('Private','Hidden') then 'Business' else 'both' end as result
from the_table
group by UserID
) t
group by result
with
my_table(user_id, label) as (values
(1,'Private'),
(1,'Public'),
(2,'Private'),
(3,'Hidden'),
(4,'Public'),
(5,'Hidden')),
t as (
select
user_id,
string_agg('{'||label||'}', '') as labels
from my_table
group by user_id),
tt as (
select
user_id,
labels,
case
when
position('{Public}' in labels) > 0 and (position('{Private}' in labels) > 0 or position('{Hidden}' in labels) > 0) then 'Both'
when
position('{Private}' in labels) > 0 or position('{Hidden}' in labels) > 0 then 'Business'
when
position('{Public}' in labels) > 0 then 'BtoC'
end as kind
from t)
select kind, count(*) from tt group by kind;
For MariaDB use GROUP_CONCAT() instead of PostgreSQL string_agg().
Note that the case statement check conditions in order of appearance and returns the value for the first satisfied condition.
PS: Using PostgreSQL's arrays the conditions would be more elegant.

Filter Duplicates in UNION with SQL Server

I am trying to remove the duplicate entries which are being caused by date values being different. I tried to use min(date) in group by but that's not allowed
For example in getting back the following 2 rows when all I need is the 1st
MasterCustomerId NewClubKeyId DateAssigned
000000201535 K18752 2014-08-13 20:25:18.717
000000201535 K18752 2015-01-08 00:41:03.037
Here is my query. Any ideas? Thanks
SELECT nc.CreatorMasterCustomerId MasterCustomerId,nc.NewClubKeyId,MIN(nc.DateCreated) DateAssigned
FROM NewClub nc
WHERE nc.IsActive = 1 AND nc.NewClubKeyId IS NOT NULL AND nc.DateCreated IS NOT NULL
AND nc.DateCreated >='2013-10-10'
GROUP BY nc.CreatorMasterCustomerId,nc.NewClubKeyId,nc.DateCreated
UNION
SELECT ncb.MasterCustomerId,nc.NewClubKeyId,MIN(ncb.DateCreated) DateAssigned
FROM NewClubBuilder ncb
JOIN NewClub nc ON nc.Id = ncb.NewClubId
WHERE nc.IsActive = 1 AND nc.NewClubKeyId IS NOT NULL AND ncb.DateCreated IS NOT NULL
AND ncb.DateCreated >='2013-10-10'
GROUP BY ncb.MasterCustomerId,nc.NewClubKeyId,ncb.DateCreated
Per the suggestion from #suslov below, I implemented the query as described and it works well. Here it is:
select
t.MasterCustomerId,
t.NewClubKeyId,
MIN(t.DateCreated)DateAssigned
FROM
(
SELECT DISTINCT nc.CreatorMasterCustomerId MasterCustomerId,nc.NewClubKeyId,nc.DateCreated
FROM NewClub nc
WHERE nc.IsActive = 1 AND nc.NewClubKeyId IS NOT NULL AND nc.DateCreated IS NOT NULL
AND nc.DateCreated >='2013-10-10'
UNION
SELECT DISTINCT ncb.MasterCustomerId,nc.NewClubKeyId,ncb.DateCreated
FROM NewClubBuilder ncb
JOIN NewClub nc ON nc.Id = ncb.NewClubId
WHERE nc.IsActive = 1 AND nc.NewClubKeyId IS NOT NULL AND ncb.DateCreated IS NOT NULL
AND ncb.DateCreated >='2013-10-10'
)t
GROUP BY t.MasterCustomerId,t.NewClubKeyId
You can use your select with union as a temporary table and then select from it and do a group by you did before without DateCreated field.
select t.CreatorMasterCustomerId as MasterCustomerId
, t..NewClubKeyId
, min(t.DateCreated) as DateAssigned
from (<...>) t
group by t.MasterCustomerId
, t.NewClubKeyId

Sql query to multiply two column value to third column

I want to multiply two columns value to 3rd column. Here is my query:
select distinct pr.PSProjectId,sfa.CodePattern, case when sfqd.NCR IS null then 'blank' else sfqd.NCR end as NCR
,
case when sfqd.NCR !='blank' then
(Select DATEDIFF(minute,starttime,EndTime) from ShopFloorStatusDetail where ShopFloorActivityId=sfa.ShopFloorActivityId
and StatusId=8
)
else
DATEDIFF(MINUTE,sfs.ShiftStarTime,sfs.shiftendtime)
end as timediff,
(select COUNT(1) from ShopFloorEmployeeTime where ShopFloorShiftId=sfs.ShopFloorShiftId) as totalemployee
from ShopFloor sf
inner join Project pr on pr.ProjectId=sf.ProjectId
inner join ShopFloorActivity sfa on sf.ShopFloorId=sfa.ShopFloorId
inner join ShopFloorShift sfs on sfs.ShopFloorActivityId=sfa.ShopFloorActivityId
left join ShopFloorStatusDetail sfsd on sfsd.ShopFloorActivityId=sfs.ShopFloorActivityId
left join ShopFloorQCDetail sfqd on sfqd.ShopFloorStatusDetailId=sfsd.ShopFloorStatusDetailId
and sfqd.NCR is not null
where CAST(sfs.ShiftStarTime as DATE) between '2014/01/06' and '2014/01/07'
and output from this query is
PSProjectId CodePattern NCR timediff totalemployee
0000129495 3TMEU blank 8 1
0000130583 3UA1P blank 1 1
0000130583 3UA1P blank 2090 2
Now i want to multiply column timediff and totalemployee and show it in a new column.
How do I do this? Please help.
Just add a new column, multiplying the existing expressions:
case when sfqd.NCR !='blank'
then (Select DATEDIFF(minute,starttime,EndTime)
from ShopFloorStatusDetail
where ShopFloorActivityId=sfa.ShopFloorActivityId
and StatusId=8
)
else DATEDIFF(MINUTE,sfs.ShiftStarTime,sfs.shiftendtime)
end
*
(select COUNT(1)
from ShopFloorEmployeeTime
where ShopFloorShiftId=sfs.ShopFloorShiftId)
Alternatively, wrap the whole existing query in another query, and multiply the calcualted columns:
select
PSProjectId,
CodePattern,
NCR,
timediff,
totalemployee,
timediff * totalemployee
from
( ...original query here... )