SQL - COMPARING MULTIPLE FIELD IN A TABLE - sql

I want to compare 3 fields value in a table.
example:column 1 - 10 items
column 2 - 7 items with 3 Null
column 3 - 4 items with 6 null
anybody can help me!
items column1 column2 column3
1 BK1 NULL BK1
2 RK1 RK1 RK1
3 SK1 SK2 NULL
4 AK1 AK1 AK2
5 CK1 CK2 CK2
6 DK1 NULL NULL
7 EK1 EK1 NULL
8 FK1 NULL NULL
9 GK1 GK1 NULL
10 HK1 NULL NULL
Reuslt
items column1 column2 column3 RESULT
1 BK1 NULL BK1 OK
2 RK1 RK1 RK1 OK
3 SK1 SK2 NULL NOT EQUAL
4 AK1 AK1 AK2 NOT EQUAL
5 CK1 CK2 CK2 NOT EQUAL
6 DK1 NULL NULL OK
7 EK1 EK1 NULL OK
8 FK1 NULL NULL OK
9 GK1 GK1 NULL OK
10 HK1 NULL NULL OK

I hope following can be helpful
select * from tablename
where (column1 is not null and column2 is not NULL and column3 is not NULL)
and (column1 = column2 or column2 = column3 or column3 = column1 )
Please check SQLFiddle example
http://sqlfiddle.com/#!3/fe38f/1

select * from tablename
where
(c1 is null or ((c2 is null or c1 = c2) and (c3 is null or c1 = c3)))
and
(c2 is null or ((c1 is null or c1 = c2) and (c3 is null or c2 = c3)))
and
(c3 is null or ((c1 is null or c1 = c3) and (c2 is null or c2 = c3)))

Related

SQL: NULL placeholder values in a TOP 10 list that returns less than ten values

I have written a query that returns a resultset of the top 10 values. This works great, but where a resultset returns a list of values that is smaller than 10 items then I would like the query to return placeholder values to pas the resultset out to ten values i.e. NULLS.
Current resultset:
SENDBottom10Prog CFC 11 Business Surname1 Forename1 11MO 50 2 4 U -4.00
SENDBottom10Prog CIN 11 Business Surname2 Forename2 11MO 86.9 0 4 2 -2.00
SENDBottom10Prog N 11 Business Surname3 Forename3 11MC 100 0 3 2 -1.00
SENDBottom10Prog N 11 Business Surname4 Forename4 11MO 97.62 5 4 6 2.00
Desirable resultset:
SENDBottom10Prog CFC 11 Business Surname1 Forename1 11MO 50 2 4 U -4.00
SENDBottom10Prog CIN 11 Business Surname2 Forename2 11MO 86.9 0 4 2 -2.00
SENDBottom10Prog N 11 Business Surname3 Forename3 11MC 100 0 3 2 -1.00
SENDBottom10Prog N 11 Business Surname4 Forename4 11MO 97.62 5 4 6 2.00
NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL
NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL
NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL
NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL
NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL
NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL
Here is my code so far:
DECLARE
#AcademicYear varchar(9) = '2019/2020',
#Collection varchar(50) = 'autumn',
#StuYear VARCHAR(2) = '11';
Select 'SENDBottom10Prog' as List, SG, Year, Subject, Surname, Forename, Form, [AM/PM], Behaviour, FFT20, Prediction, Residual
From (
SELECT s.sg, s.Year,r.Subject as 'Subject', s.Surname, s.Forename, s.Form,s.attendance as 'AM/PM', s.behaviour, r.Target as FFT20, r.Prediction, g3.Points-g2.Points as Residual, g3.graderank, row_number() over(partition by r.subject order by s.year, r.subject, cast(g3.Points-g2.Points as decimal) asc, g3.graderank asc, Attendance asc, Behaviour, s.Surname, s.Forename) as rn
FROM Results r
LEFT JOIN Grades g1
ON r.Result = g1.Grade
LEFT JOIN Grades g2
ON r.Target = g2.Grade
LEFT JOIN Grades g3
ON r.Prediction = g3.Grade
LEFT JOIN students s
ON r.UPN = s.UPN
WHERE r.AcademicYear = #AcademicYear
AND s.AcademicYear = #AcademicYear
AND r.Collection = #Collection
AND s.year=#StuYear
AND SEND='Y'
AND s.NotIncluded = 'N'
) as T
where T.rn <=10;
If you want to get exactly ten rows, but don't have them, then you need to construct them. Here is one method:
with t as (
< your query here >
)
select t.*
from (values (1), (2), (3), (4), (5), (6), (7), (8), (9), (10)
) v(n) left join
t
on t.rn = v.n
order by v.n;

SQL Server - complete results with non existent data

I have a table where I have all the customers and a table where I have all their restrictions.
CUSTOMER
customer_id customer_name
1 name 1
2 name 2
CUSTOMER_RESTRICTIONS
rest_type day_of_week hour_start hour_stop customer_id
TYPE1 0 08:00 12:00 1
TYPE1 0 13:00 17:00 1
TYPE2 0 17:00 23:59 1
Problem: I only have a record for a restriction type and a customer when the customer has a restriction and this is a problem in the visualization I want to build.
I need every customer, every day and every restriction type, even when there is no restriction. In that case hour_start and hour_stop would be NULL.
For the tables shown, the output would be
rest_type day_of_week hour_start hour_stop customer_id
TYPE1 0 08:00 12:00 1
TYPE1 0 08:00 12:00 1
TYPE1 1 NULL NULL 1
TYPE1 2 NULL NULL 1
TYPE1 3 NULL NULL 1
TYPE1 4 NULL NULL 1
TYPE1 5 NULL NULL 1
TYPE1 6 NULL NULL 1
TYPE1 1 NULL NULL 1
TYPE1 2 NULL NULL 1
TYPE1 3 NULL NULL 1
TYPE1 4 NULL NULL 1
TYPE1 5 NULL NULL 1
TYPE2 0 NULL NULL 1
TYPE2 1 NULL NULL 1
TYPE2 2 NULL NULL 1
TYPE2 3 NULL NULL 1
TYPE2 4 NULL NULL 1
TYPE2 5 NULL NULL 1
TYPE2 6 NULL NULL 1
TYPE1 0 NULL NULL 2
TYPE1 1 NULL NULL 2
TYPE1 2 NULL NULL 2
TYPE1 3 NULL NULL 2
TYPE1 4 NULL NULL 2
TYPE1 5 NULL NULL 2
TYPE1 6 NULL NULL 2
TYPE2 0 NULL NULL 2
TYPE2 1 NULL NULL 2
TYPE2 2 NULL NULL 2
TYPE2 3 NULL NULL 2
TYPE2 4 NULL NULL 2
TYPE2 5 NULL NULL 2
TYPE2 6 NULL NULL 2
How can I achieve that? I couldn't even start to build this query.
Essentially you need to start with the data you must have and left join the optional data. E.g., something like this:
select c.customer_id
,r.[rest_type]
,d.[day_of_week]
,r.[hour_start]
,r.[hour_stop]
from CUSTOMER c
cross apply (
select 0 as day_of_week
union all select 1
union all select 2
union all select 3
union all select 4
union all select 5
union all select 6
) d
left join CUSTOMER_RESTRICTIONS r on c.customer_id = r.customer_id and d.day_of_week = r.day_of_week
Output:
customer_id rest_type day_of_week hour_start hour_stop
----------- --------- ----------- ---------- ---------
1 TYPE1 0 08:00 12:00
1 TYPE1 0 13:00 17:00
1 TYPE2 0 17:00 23:59
1 NULL 1 NULL NULL
1 NULL 2 NULL NULL
1 NULL 3 NULL NULL
1 NULL 4 NULL NULL
1 NULL 5 NULL NULL
1 NULL 6 NULL NULL
If there are only type rest_types, you don't have a lookup table for them, and you want to show a row for each, you would do:
select c.customer_id
,t.[rest_type]
,d.[day_of_week]
,r.[hour_start]
,r.[hour_stop]
from CUSTOMER c
cross apply (
select 0 as day_of_week
union all select 1
union all select 2
union all select 3
union all select 4
union all select 5
union all select 6
) d
cross apply (
select 'TYPE1' as rest_type
union all select 'TYPE2'
) t
left join CUSTOMER_RESTRICTIONS r on c.customer_id = r.customer_id
and d.day_of_week = r.day_of_week
and t.rest_type = r.rest_type
(select rest_type, day_of_week,
hour_start ,
hour_stop
from table A
where rest_type IS NOT NULL)
Union
(select rest_type,
day_of_week,
NULL ,NULL
from table A
where rest_type IS NULL)
Is this what you want ?
First off, I wouldn't store rest type as you are, that is a bad habit, it should be a reference table!
You need to cross apply to get all your possible combinations, and then add in the values you DO have...
DECLARE #Customer TABLE (Id INT IDENTITY(1,1), Name NVARCHAR(100))
DECLARE #Rest TABLE (Id INT IDENTITY(1,1), Name NVARCHAR(100))
DECLARE #Restrictions TABLE (Id INT IDENTITY(1,1), RestID INT, CustomerID INT, Day_of_Week TINYINT, hour_start TIME, hour_end TIME)
INSERT INTO #Customer (NAME)
VALUES('JOHN'),('SUSAN')
INSERT INTO #Rest (NAME)
VALUES ('TYPE A'),('TYPE B')
INSERT INTO #Restrictions (RestID,CustomerID,Day_of_Week,hour_start,hour_end)
VALUES (1,1,0,'08:00','12:00'),
(1,1,0,'13:00','17:00'),
(1,2,0,'17:00','23:59')
;WITH DaysofWeek AS
(
SELECT 0 AS dow
UNION ALL
SELECT dow+1
FROM DaysofWeek
WHERE dow<5
)
SELECT *
FROM #Customer C
CROSS APPLY #Rest R
CROSS APPLY DaysofWeek D
LEFT JOIN #Restrictions X
ON X.Day_of_Week=D.dow
AND X.CustomerID=C.Id
AND X.RestID=R.Id
ORDER BY C.Id, D.dow, R.Id

How will I remove nulls from each columns

How will I remove nulls from each columns
This is the example
Column 1 Column 2 column 3 column 4
a 1 null null
b 0 null null
c 1 null null
a null 0 null
b null 1 null
c null 0 null
a null null 1
b null null 1
c null null 0
I want it to look like this
Column 1 Column 2 column 3 column 4
a 1 0 1
b 0 1 1
c 1 0 0
Is this possible?
You may see attached pictures for before and after image.
You can use aggregation:
select col1, max(col2) as col2, max(col3) as col3, max(col4) as col4
from t
group by col1;

Retrieving data from specific columns of multiple rows in sql

I have a table which stores information as follows and has ID as the primary key:
Link for the table view: https://drive.google.com/file/d/0B4UzXmbWLTJZaU84WnVZMUJDT3M/view?usp=sharing
ID ScheduleDate WorkArea Employee1 Hours1 Employee2 Hours2 Employee3 Hours3 Employee4 Hours4 Employee5 Hours5 Employee6 Hours6 Employee7 Hours7 Employee8 Hours8
1 7/1/2014 W1 A 8 B 7 C 4 D 3 NULL 0 NULL 0 NULL 0 NULL 0
2 7/1/2014 W2 B 8 C 8 0 0 0 0 NULL
3 7/1/2014 W3 C 8 A 8 E 8 F 8 NULL NULL NULL NULL NULL NULL NULL NULL
4 7/1/2014 W4 D 8 B 8 F 8 NULL NULL NULL NULL NULL NULL
5 7/1/2014 W5 E 8 C 8 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL
6 7/1/2014 W6 F 8 D 8 8 NULL NULL NULL NULL NULL NULL NULL NULL NULL
7 8/1/2014 W1 G 4 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL
8 8/1/2014 W2 A 4 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL
9 8/1/2014 W3 B 8 F 8 8 8 NULL NULL NULL NULL NULL NULL NULL NULL
For any particular ScheduleDate, there can be only one WorkArea (combination of ScheduleDate and WorkArea is unique). Now, I want to check if the sum of hours of the particular employee is greater than 8 hours or not in any single date. For example, the sum of hours of employee A for the particular date (can be hour1, hour2 or anything based on employee's placement in the table) should not be more than 8 hours. How do I check that?
Please help.
Thanks
You don't really strictly need the aliases on each of the union-ed queries:
with t as (
select ScheduleDate, Workarea, Employee1 as Employee, Hours1 as Hrs union all
select ScheduleDate, Workarea, Employee2 as Employee, Hours2 as Hrs union all
...
select ScheduleDate, Employee8 as Employee, Hours8 as Hrs
)
select ScheduleDate, Employee, sum(Hrs) as [Hours]
from t
group by ScheduleDate, Employee
having sum(Hrs) > 8

Using Boolean to determine 5-way Where clause

I'm looking at 5 different columns (db made badly unfortunately). If of the five columns two have one "1" value and one "2" value I want this record to be excluded from the results. However, if it only has one of the two values I want it to be included.
I have this so far, but I'm certain it will not include the record if it has even one of the two values.
NOT ((Ew.DocRecvd1 = 10 OR Ew.DocRecvd1 = 11) OR
(Ew.DocRecvd2 = 10 OR Ew.DocRecvd2 = 11) OR
(Ew.DocRecvd3 = 10 OR Ew.DocRecvd3 = 11) OR
(Ew.DocRecvd4 = 10 OR Ew.DocRecvd4 = 11) OR
(Ew.DocRecvd5 = 10 OR Ew.DocRecvd5 = 11))
Thanks.
I would suggest that you count the number of values in each group that you want. And, I would do it in a subquery, just because that makes the code more readable and maintainable.
Here is an example:
from (select t.*,
((case when Ew.DocRecvd1 in (10, 11) then 1 else 0) +
(case when Ew.DocRecvd2 in (10, 11) then 1 else 0) +
(case when Ew.DocRecvd3 in (10, 11) then 1 else 0) +
(case when Ew.DocRecvd4 in (10, 11) then 1 else 0) +
(case when Ew.DocRecvd5 in (10, 11) then 1 else 0) +
) as Num1s,
<something similar> as Num2s
from table t
) t
where Num1s = 2 and Num2s = 1;
You state the filter conditions simply in the where clause. Given a table
create table foobar
(
id int not null primary key ,
c1 int not null ,
c2 int not null ,
c3 int not null ,
c4 int not null ,
c5 int not null ,
)
go
You can say
select *
from foobar
where not ( 2 = case c1 when 1 then 1 else 0 end
+ case c2 when 1 then 1 else 0 end
+ case c3 when 1 then 1 else 0 end
+ case c4 when 1 then 1 else 0 end
+ case c5 when 1 then 1 else 0 end
and 1 = case c1 when 2 then 1 else 0 end
+ case c2 when 2 then 1 else 0 end
+ case c3 when 2 then 1 else 0 end
+ case c4 when 2 then 1 else 0 end
+ case c5 when 2 then 1 else 0 end
)
The other approach which might run faster is to use as mask table, containing the conditions you want to exclude. Something like this one:
create table mask
(
c1 tinyint null ,
c2 tinyint null ,
c3 tinyint null ,
c4 tinyint null ,
c5 tinyint null ,
unique clustered ( c1,c2,c3,c4,c5) ,
)
In your case, there are only 30 conditions to be excluded:
c1 c2 c3 c4 c5
---- ---- ---- ---- ----
NULL NULL 1 1 2
NULL NULL 1 2 1
NULL NULL 2 1 1
NULL 1 NULL 1 2
NULL 1 NULL 2 1
NULL 1 1 NULL 2
NULL 1 1 2 NULL
NULL 1 2 NULL 1
NULL 1 2 1 NULL
NULL 2 NULL 1 1
NULL 2 1 NULL 1
NULL 2 1 1 NULL
1 NULL NULL 1 2
1 NULL NULL 2 1
1 NULL 1 NULL 2
1 NULL 1 2 NULL
1 NULL 2 NULL 1
1 NULL 2 1 NULL
1 1 NULL NULL 2
1 1 NULL 2 NULL
1 1 2 NULL NULL
1 2 NULL NULL 1
1 2 NULL 1 NULL
1 2 1 NULL NULL
2 NULL NULL 1 1
2 NULL 1 NULL 1
2 NULL 1 1 NULL
2 1 NULL NULL 1
2 1 NULL 1 NULL
2 1 1 NULL NULL
(30 row(s) affected)
The actual query is trivial then (and if you have a covering index on the columns to be tested, the test is done with index seeks and so should perform extremely well:
select *
from dbo.foobar t
where not exists ( select *
from mask m
where t.c1 = m.c1
and t.c2 = m.c2
and t.c3 = m.c3
and t.c4 = m.c4
and t.c5 = m.c6
)
The advantage of this approach is that the ruleset is table-driven, meaning future changes to the rules are just data modifications to your mask table.
You could also use a positive set of rules, but in your case, the set is bigger (>200 positive cases as opposed to the 30 negative cases).
OK, I think I've found the result I wanted.
I used the following in the WHERE clause of my query:
NOT
(2 =
(CASE WHEN Ew.DocRecvd1 = 10 THEN 1 ELSE 0 END
+
CASE WHEN Ew.DocRecvd2 = 10 THEN 1 ELSE 0 END
+
CASE WHEN Ew.DocRecvd3 = 10 THEN 1 ELSE 0 END
+
CASE WHEN Ew.DocRecvd4 = 10 THEN 1 ELSE 0 END
+
CASE WHEN Ew.DocRecvd5 = 10 THEN 1 ELSE 0 END
+
CASE WHEN Ew.DocRecvd1 = 11 THEN 1 ELSE 0 END
+
CASE WHEN Ew.DocRecvd2 = 11 THEN 1 ELSE 0 END
+
CASE WHEN Ew.DocRecvd3 = 11 THEN 1 ELSE 0 END
+
CASE WHEN Ew.DocRecvd4 = 11 THEN 1 ELSE 0 END
+
CASE WHEN Ew.DocRecvd5 = 11 THEN 1 ELSE 0 END))
It is only possible in my DB to get these two documents in one of five places within one record, so the count could not go over 2 with the two documents i'm looking for.
Kudos to Nicholas Carey and Gordon Linoff for keying me into what I could do and look for!