SQL join to identify group members - sql

I have got a client table which pretty much looks like below:
Client List
customer no. Customer name
123 Kristen Smith
128 Jeremy Church
127 Alan Li
132 Ryan Nelson
I need to map it to a Customer_Dim table
Customer_Dim
customer no. Customer name Group no. Group Name Cust_Active Flag
123 Kristen Smith 5491 Zealong Tea Estate Y
167 Anna Hathaway 5823 AA Insurance Y
146 Simon Joe 5671 Direct Automobile Y
148 Henry Wilson 5823 AA Insurance Y
195 Graham Brown 5491 Zealong Tea Estate Y
172 Daria Smith 5671 Direct Automobile N
122 Dyana Smith 5823 AA Insurance N
132 Ryan Nelson 5671 Direct Automobile N
128 Jeremy Church 5823 AA Insurance Y
127 Alan Li 5671 Direct Automobile Y
to get their group numbers from below table (which I am able to do by a simple left join)
to list all the remaining customers (who are active) from the group numbers of the client customer [I AM UNABLE TO DO THIS 2nd PART] :
Required Results :
Customer No. Customer name Group No. Group Name
123 Kristen Smith 5491 Zealong Tea Estate
128 Jeremy Church 5823 AA Insurance
127 Alan Li 5671 Direct Automobile
195 Graham Brown 5491 Zealong Tea Estate
167 Anna Hathaway 5823 AA Insurance
148 Henry Wilson 5823 AA Insurance
146 Simon Joe 5671 Direct Automobile
Please let me know if any other information is needed.
Sorry, if a similar question has been asked earlier - did several searches but was unable to find anything.
Thanks

join the tables to get all the group numbers of the clients in the client list and then select from customer_dim only the clients of these group numbers who are active:
select * from customer_dim
where
cust_active_flag = 'Y'
and
groupno in (
select groupno
from client_list l inner join customer_dim d
on d.customerno = l.customerno
)
See the demo.
Results:
> customerno | customername | groupno | groupname | cust_active_flag
> ---------: | :------------ | ------: | :----------------- | :---------------
> 123 | Kristen Smith | 5491 | Zealong Tea Estate | Y
> 167 | Anna Hathaway | 5823 | AA Insurance | Y
> 146 | Simon Joe | 5671 | Direct Automobile | Y
> 148 | Henry Wilson | 5823 | AA Insurance | Y
> 195 | Graham Brown | 5491 | Zealong Tea Estate | Y
> 128 | Jeremy Church | 5823 | AA Insurance | Y
> 127 | Alan Li | 5671 | Direct Automobile | Y

for get required results you need a condition in your join
SELECT *
FROM Client c
JOIN Customer_Dim cd on c.CustomerNo = cd.CustomerNo
and cd.Cust_ActiveFlag ='Y'
or
SELECT *
FROM Client c
JOIN Customer_Dim cd on c.CustomerNo = cd.CustomerNo
WHERE cd.Cust_ActiveFlag ='Y'

I think it is pretty simple to get your posted result from Customer_Dim table.
if you don't want Group No. of ClientList
select * from Customer_Dim
where [Cust_Active Flag] = 'Y'
and [Group No.] not in (
select CD.[Group No.] from [Client List] as CL inner join Customer_Dim as CD where CL.[customer no.] = CD.[customer no.] )
And
if you only want Group No. of ClientList
select * from Customer_Dim
where [Cust_Active Flag] = 'Y'
and [Group No.] in (
select CD.[Group No.] from [Client List] as CL inner join Customer_Dim as CD where CL.[customer no.] = CD.[customer no.] )

For the case of a client being inactive and wanting to identify the client in the result set you can do a LEFT JOIN with a GROUP BY and leverage Proc SQL automatic remerging in a HAVING clause for selection criteria.
data client_list; input
custno custname:& $30.; datalines;
123 Kristen Smith
128 Jeremy Church
127 Alan Li
132 Ryan Nelson
899 Julius Caesar
run;
data customer_dim; input
custno custname:& $30. groupnum groupname:& $30. Cust_Active_Flag: $1.; datalines;
123 Kristen Smith 5491 Zealong Tea Estate Y
167 Anna Hathaway 5823 AA Insurance Y
146 Simon Joe 5671 Direct Automobile Y
148 Henry Wilson 5823 AA Insurance Y
195 Graham Brown 5491 Zealong Tea Estate Y
172 Daria Smith 5671 Direct Automobile N
122 Dyana Smith 5823 AA Insurance N
132 Ryan Nelson 5671 Direct Automobile N
128 Jeremy Church 5823 AA Insurance Y
127 Alan Li 5671 Direct Automobile Y
231 Donald Duck 7434 Orange Insurance Y
899 Julius Caesar 4999 Emperors N
900 Joshua Norton 4999 Emperors N
925 Joaquin Guzman 4999 Emperors Y
925 Naruhito 4999 Emperors Y
run;
proc sql;
create table want(label="Active customers of clients groups") as
select
LIST.custno as client,
DIM.*
from
customer_dim DIM
left join
client_list LIST
on
DIM.custno = LIST.custno
group by
groupnum
having
N(LIST.custno) > 0
and
(
cust_active_flag = 'Y'
or LIST.custno is not NULL
)
order by
groupnum, custno
;

Related

Presenting Data uniformly between two different table presentations with SQL

Hello Everyone I have a problem…
Table 1 (sorted) is laid out like this:
User ID Producer ID Company Number
JWROSE 23401 234
KXPEAR 23903 239
LMWEEM 27902 279
KJMORS 18301 183
Table 2 (unsorted) looks like this:
Client Name City Company Number
Rajat Smith London JWROSE
Robert Singh Cleveland KXPEAR
Alberto Johnson New York City LMWEEM
Betty Lee Dallas KJMORS
Chase Galvez Houston 23401
Hassan Jackson Seattle 23903
Tooti Fruity Boise 27902
Joe Trump Tokyo 18301
Donald Biden Cairo 234
Mike Harris Rome 239
Kamala Pence Moscow 279
Adolf Washington Bangkok 183
Now… Table 1 has all of the User IDs and Producer IDs properly rowed with the Company Number.
I want to pull all the data and correctly sorted….
Client Name City User ID Producer ID Company Number
Rajat Smith London JWROSE 23401 234
Robert Singh Cleveland KXPEAR 23903 239
Alberto Johnson New York City LMWEEM 27902 279
Betty Lee Dallas KJMORS 18301 183
Chase Galvez Houston JWROSE 23401 234
Hassan Jackson Seattle KXPEAR 23903 239
Tooti Fruity Boise LMWEEM 27902 279
Joe Trump Tokyo KJMORS 18301 183
Donald Biden Cairo JWROSE 23401 234
Mike Harris Rome KXPEAR 23903 239
Kamala Pence Moscow LMWEEM 27902 279
Adolf Washington Bangkok KJMORS 18301 183
Query:
Select
b.client_name,
b.city.,
a.user_id,
a.producer_id,
a.company_number
From Table 1 A
Left Join Table 2 B On a.company….
And this is where I don’t know what do to….because both tables have all the same variables, but Company Number in Table 2 is mixed with User IDs and Producer IDs... however we know what company Number those ID's are associated to.
As I mention in the comments, and others do, the real problem is your design. "The fact that UserID is clearly a varchar, while the other 2 columns are an int really does not make this any better", and makes this not simple (and certainly not SARGable).
To get the data in the correct order, as well, you need a column to order it on which the data lacks. I have therefore added a pseudo column, MissingIDColumn, to represent this missing column you need to add to your data; which you can do when you fix the design:
SELECT T2.ClientName,
T2.City,
T1.UserID,
T1.ProducerID,
T1.CompanyNumber
FROM (VALUES('JWROSE',23401,234),
('KXPEAR',23903,239),
('LMWEEM',27902,279),
('KJMORS',18301,183))T1(UserID,ProducerID,CompanyNumber)
JOIN (VALUES(1,'Rajat Smith ','London ','JWROSE'),
(2,'Robert Singh ','Cleveland ','KXPEAR'),
(3,'Alberto Johnson ','New York City','LMWEEM'),
(4,'Betty Lee ','Dallas ','KJMORS'),
(5,'Chase Galvez ','Houston ','23401'),
(6,'Hassan Jackson ','Seattle ','23903'),
(7,'Tooti Fruity ','Boise ','27902'),
(8,'Joe Trump ','Tokyo ','18301'),
(9,'Donald Biden ','Cairo ','234'),
(10,'Mike Harris ','Rome ','239'),
(11,'Kamala Pence ','Moscow ','279'),
(12,'Adolf Washington','Bangkok ','183'))T2(MissingIDColumn,ClientName,City,CompanyNumber) ON T2.CompanyNumber IN (T1.UserID,CONVERT(varchar(6),T1.ProducerID),CONVERT(varchar(6),T1.CompanyNumber))
ORDER BY MissingIDColumn;

How should I write the JOIN clause to make it work well?

I'm doing Q4 (Find the titles of all movies not reviewed by Chris Jackson. ) from SQL Movie-Rating Query Exercises Extras and I don't know why this code doesn't work:
SELECT DISTINCT movie.title
FROM movie
INNER JOIN rating ON movie.mid = rating.mID
INNER JOIN reviewer ON rating.rid = reviewer.rid
WHERE rating.mid NOT IN (SELECT rating.mid FROM rating WHERE rating.rid = (SELECT reviewer.rid FROM reviewer WHERE reviewer.name = 'Chris Jackson') )
Output:
title
Gone with the Wind
Snow White
Avatar
This output doesn't include movies that ARE in movie table but ARE NOT in rating table. So I suspect maybe this has something to do with JOIN clause.
TABLES:
Movie
mID title year director
101 Gone with the Wind 1939 Victor Fleming
102 Star Wars 1977 George Lucas
103 The Sound of Music 1965 Robert Wise
104 E.T. 1982 Steven Spielberg
105 Titanic 1997 James Cameron
106 Snow White 1937 <null>
107 Avatar 2009 James Cameron
108 Raiders of the Lost Ark 1981 Steven Spielberg
Reviewer
rID name
201 Sarah Martinez
202 Daniel Lewis
203 Brittany Harris
204 Mike Anderson
205 Chris Jackson
206 Elizabeth Thomas
207 James Cameron
208 Ashley White
Rating
rID mID stars ratingDate
201 101 2 2011-01-22
201 101 4 2011-01-27
202 106 4 <null>
203 103 2 2011-01-20
203 108 4 2011-01-12
203 108 2 2011-01-30
204 101 3 2011-01-09
205 103 3 2011-01-27
205 104 2 2011-01-22
205 108 4 <null>
206 107 3 2011-01-15
206 106 5 2011-01-19
207 107 5 2011-01-20
208 104 3 2011-01-02
Firstly you must use LEFT JOIN and then then use GROUP BY movie.mid, movie.title and put the condition in the HAVING clause:
SELECT movie.title
FROM movie
LEFT JOIN rating ON movie.mid = rating.mID
LEFT JOIN reviewer ON rating.rid = reviewer.rid
GROUP BY movie.mid, movie.title
HAVING SUM(CASE WHEN reviewer.name = 'Chris Jackson' THEN 1 ELSE 0 END) = 0
See the demo.
Results:
> | title |
> | :----------------- |
> | Avatar |
> | Gone with the Wind |
> | Snow White |
> | Star Wars |
> | Titanic |
Although you can use aggregation, I would recommend NOT EXISTS for this purpose. It is close to the phrasing of the logic you want:
SELECT m.*
FROM movie m
WHERE NOT EXISTS (SELECT 1
FROM rating r JOIN
reviewer re
ON r.rid = re.rid
WHERE m.mid = r.mID AND
re.name = 'Chris Jackson'
);
There should simply be no comparison from a performance perspective. This should have much better performance.

SQL logic for getting records in a single row for a unique id

![Cognost reports studio Query Explorer]
Below is the snapshot of a table.
**Acctno ClientNo ClientName PrimaryOffId SecondaryOffID**
101 11111 ABC corp 3 Not Defined
102 11116 XYZ Inc 5 Not Defined
103 11113 PQRS Corp 2 9
104 55555 Food LLC 4 11
105 99999 Kwlg Co 1 Not Defined
106 99999 Kwlg Co 1 Not Defined
107 11112 LMN Corp Not Defined 6
108 11112 LMN Corp Not Defined 6
109 11115 Sleep Co 4 10
110 44444 Cool Co Not Defined 8
111 11114 Sail LLC 3 Not Defined
112 66666 Fun Inc 1 Not Defined
113 88888 Job LLC 5 12
114 22222 Acc Co Not Defined Not Defined
115 77777 Good Corp 2 Not Defined
116 33333 City LLC Not Defined 7
117 33333 City LLC Not Defined 7
118 33333 City LLC Not Defined 7
119 11111 ABC corp 3 Not Defined
I want to replace PrimaryOffID and SecondaryOffID with their Names coming from this table
EmpID Names
1 Cathy
2 Chris
3 John
4 Kevin
5 Mark
6 Celine
7 Jane
8 Phil
9 Jess
10 Jose
11 Nick
12 Rosy
The Result should look like this: Notice that, If Cathy is the PrimaryOfficer, she can't be the Secondary Officer and vice versa. This logic is applicable for all the Names
Acctno ClientNo Client Name PrimOffName SecondaryOffName
101 11111 ABC corp John Not Defined
102 11116 XYZ Inc Mark Not Defined
103 11113 PQRS Corp Chris Jess
104 55555 Food LLC Kevin Nick
105 99999 Kwlg Co Cathy Not Defined
106 99999 Kwlg Co Cathy Not Defined
107 11112 LMN Corp Not Defined Celine
108 11112 LMN Corp Not Defined Celine
109 11115 Sleep Co Kevin Jose
110 44444 Cool Co Not Defined Phil
111 11114 Sail LLC John Not Defined
112 66666 Fun Inc Cathy Not Defined
113 88888 Job LLC Mark Rosy
114 22222 Acc Co Not Defined Not Defined
115 77777 Good Corp Chris Not Defined
116 33333 City LLC Not Defined Jane
117 33333 City LLC Not Defined Jane
118 33333 City LLC Not Defined Jane
119 11111 ABC corp John Not Defined
But Instead it looks like this:
Acctno ClientNo ClientName PrimOffName SecondaryOffName
101 11111 ABC corp John Not Defined
102 11116 XYZ Inc Mark Not Defined
103 11113 PQRS Corp Chris Not Defined
103 11113 PQRS Corp Not Defined Jess
104 55555 Food LLC Kevin Not Defined
104 55555 Food LLC Not Defined Nick
105 99999 Kwlg Co Cathy Not Defined
106 99999 Kwlg Co Cathy Not Defined
107 11112 LMN Corp Not Defined Celine
108 11112 LMN Corp Not Defined Celine
109 11115 Sleep Co Kevin Not Defined
109 11115 Sleep Co Not Defined Jose
110 44444 Cool Co Not Defined Phil
111 11114 Sail LLC John Not Defined
112 66666 Fun Inc Cathy Not Defined
113 88888 Job LLC Mark Not Defined
113 88888 Job LLC Not Defined Rosy
114 22222 Acc Co Not Defined Not Defined
115 77777 Good Corp Chris Not Defined
116 33333 City LLC Not Defined jane
117 33333 City LLC Not Defined jane
118 33333 City LLC Not Defined jane
119 11111 ABC corp John Not Defined
Notice that, now the Acctno is no more unique, Where ever the Names should have been in both the fields together, it separates and gives the output in the next row creating multiple records. i tried various options but it didn't work. Please be aware, that I am creating this report in Cognos Studio. Please suggest the possible query to get the desired result. Thanks in Advance. Appreciate your help.
You don't state which version of Cognos you're using. "Cognos Studio" is ambiguous. I'm most familiar with 8.4.1, but even then you don't say if you're trying to define this in the Cognos model, Query Studio, Event Studio or Report Studio.
Second, you should always show what you've got so far when asking questions on StackOverflow. People want to see what you have done to show you want to fix, not repeat the lion's share of the work. That's why you got downvotes.
As far as plain SQL, you'll want to do this:
SELECT a.Acctno, a.ClientNo, a.ClientName, coalesce(e1.Names,'Not Defined') "PrimaryOffName", coalesce(e2.Names,'Not Defined') "SecondaryOffName"
FROM Account a
LEFT OUTER JOIN Emp e1
ON t.PrimaryOffID = e1.EmpID
LEFT OUTER JOIN Emp e2
ON t.PrimaryOffID = e2.EmpID
I made up table names. You can do this in Report Studio by creating two queries for Emp and outer joining them in succession to the Account query.
If you're able to, you'll want to move the OffID fields to a separate juntion table and remove them from the Account table. You can then create a Status field or flag in that junction table that identifies primary and secondary.

Copy rows of data in SQL Server

Please help me come up with a solution for the situation being explained below:
ID name address age hobby GPA
---------------------------------------------------------
101 James 100 Garfield St 21 reading 3.13
101 James 100 Garfield St 21 writing 2.63
101 James 100 Garfield St 21 running 3.81
109 Tom 19 Lily Ave 19 dating 3.54
109 Tom 20 Lily Ave 19 climbing 2.76
109 Tom 21 Lily Ave 19 watching 3.91
I want to copy the set of rows with the same ID (eg. 101) and assign each set a State abbreviation(s) by running a single sql query. For instance: adding states CA, NJ, and DE to rows with an ID of 101, the result set is expected to look like this:
ID name address age hobby GPA state
-----------------------------------------------------------------------
101 James 100 Garfield St 21 reading 3.13 CA
101 James 100 Garfield St 21 writing 2.63 CA
101 James 100 Garfield St 21 running 3.81 CA
101 James 100 Garfield St 21 reading 3.13 NJ
101 James 100 Garfield St 21 writing 2.63 NJ
101 James 100 Garfield St 21 running 3.81 NJ
101 James 100 Garfield St 21 reading 3.13 DE
101 James 100 Garfield St 21 writing 2.63 DE
101 James 100 Garfield St 21 running 3.81 DE
Please keep in mind that everything else remains the same way as they were before the addition of the state abbreviations. Also assume I have more than three states to add and integrate to the query, say, I have all 50 states. Thank you for your time and effort in advance!
This should produce that result set:
select x.*, y.st
from tbl x
join
(select 'CA' as st union all
select 'NJ' union all
select 'DE') y
where x.id = 101
Create a new table with IDs and States
ID ST
101 CA
101 NJ
101 DE
109 ..
then join that on your table
SELECT t.*, s.st
FROM tbl t
JOIN states s ON t.id = s.id

How I select record that not appear in another table

Table: Movie
mID title year director
101 Gone with the Wind 1939 Victor Fleming
102 Star Wars 1977 George Lucas
103 The Sound of Music 1965 Robert Wise
104 E.T. 1982 Steven Spielberg
105 Titanic 1997 James Cameron
106 Snow White 1937 <null>
107 Avatar 2009 James Cameron
108 Raiders of the Lost Ark 1981 Steven Spielberg
Table: Rating
rID mID stars ratingDate
201 101 2 2011-01-22
201 101 4 2011-01-27
202 106 4 <null>
203 103 2 2011-01-20
203 108 4 2011-01-12
203 108 2 2011-01-30
204 101 3 2011-01-09
205 103 3 2011-01-27
205 104 2 2011-01-22
205 108 4 <null>
206 107 3 2011-01-15
206 106 5 2011-01-19
207 107 5 2011-01-20
208 104 3 2011-01-02
I need to fetch movies which are not rate yet. In this case Titanic (mID 105) and Star Wars (mID 102) never get rate in rating table.
I figured out it with
select distinct movie.title from movie,rating where
rating.mid!=movie.mid except select distinct movie.title from
movie,rating where rating.mid=movie.mid
however I think it might have better (easier/cleaner) way to do.
Simple:
SELECT Movies.* FROM Movies LEFT JOIN Rating ON Movies.mID = Rating.mID WHERE Rating.mID IS NULL
If I understood your question properly, that looks like textbook application of outer joins.
You could do it like this:
SELECT * FROM Movie WHERE mid NOT IN (SELECT DISTINCT(mid) FROM Rating)
Basically it will select all records from the movie table that are not in the rating table, linking them on the 'mid' column, which I am assuming is a unique identifier.
I will add another possibility.
Select [list columns here]
from Movie m
where NOT exists (SELECT * FROM RATING r where m.mid = r.mid)