I have the following table,
CREATE TABLE AGENT (
A_CODE int,
A_FNAME varchar(15),
S_CODE int /* supervisor */
);
INSERT INTO AGENT VALUES(1,'John',1);
INSERT INTO AGENT VALUES(2,'Nancy',1);
INSERT INTO AGENT VALUES(3,'Lottie',2);
INSERT INTO AGENT VALUES(4,'Jennie',1);
INSERT INTO AGENT VALUES(5,'Robert',3);
INSERT INTO AGENT VALUES(6,'Cary',1);
INSERT INTO AGENT VALUES(7,'Roberto',3);
INSERT INTO AGENT VALUES(8,'Elizabeth',1);
INSERT INTO AGENT VALUES(9,'Jack',2);
INSERT INTO AGENT VALUES(10,'Rose',4);
INSERT INTO AGENT VALUES(11,'Tom',3);
INSERT INTO AGENT VALUES(12,'Alan',2);
INSERT INTO AGENT VALUES(13,'Peter',3);
INSERT INTO AGENT VALUES(14,'Sherry',4);
INSERT INTO AGENT VALUES(15,'Howard',5);
INSERT INTO AGENT VALUES(16,'Barry',5);
INSERT INTO AGENT VALUES(17,'Jeanine',4);
INSERT INTO AGENT VALUES(18,'Andrew',4);
INSERT INTO AGENT VALUES(19,'Peter',4);
INSERT INTO AGENT VALUES(20,'Robert',1);
INSERT INTO AGENT VALUES(21,'Jennifer',3);
My goal is to create a supervisor view in which there is a 4th column that has the name of the supervisor that matches the S code.
My query returns to me either nothing except the column headers or a never ending recursion that loops into the 100,000's.
What I've written is
WITH SUPERVISOR AS
(
SELECT A_CODE, A_FNAME, S_CODE, CAST('' AS VARCHAR(50)) S_NAME FROM AGENT
UNION ALL
SELECT A.A_CODE,A.A_FNAME, A.S_CODE,CAST(S.A_FNAME AS VARCHAR(50)) S_NAME FROM AGENT AS A
INNER JOIN SUPERVISOR AS S ON S.A_CODE=A.S_CODE
)
SELECT * FROM SUPERVISOR
option (maxrecursion 0);
Returns endlessly,
or
WITH SUPERVISOR AS
(
SELECT A_CODE, A_FNAME, S_CODE, CAST('' AS VARCHAR(50)) S_NAME FROM AGENT WHERE S_CODE is NULL
UNION ALL
SELECT A.A_CODE,A.A_FNAME, A.S_CODE,CAST(S.A_FNAME AS VARCHAR(50)) S_NAME FROM AGENT AS A
INNER JOIN SUPERVISOR AS S ON S.A_CODE=A.S_CODE
)
SELECT * FROM SUPERVISOR
option (maxrecursion 0);
I've been trying to read about this and figure it out on my own but at this point I've struggled for long enough that I think I need it explained to me as to why it's not working or how wildly wrong I'm going about this.
Please try the following solution. It is using self-join approach with two aliases for the same table: e(mployee) and s(upervisor).
SQL
-- DDL and sample data population, start
DECLARE #AGENT TABLE (A_CODE INT PRIMARY KEY, A_FNAME varchar(15), S_CODE int /* supervisor */);
INSERT INTO #AGENT VALUES
(1,'John',1)
,(2,'Nancy',1)
,(3,'Lottie',2)
,(4,'Jennie',1)
,(5,'Robert',3)
,(6,'Cary',1)
,(7,'Roberto',3)
,(8,'Elizabeth',1)
,(9,'Jack',2)
,(10,'Rose',4)
,(11,'Tom',3)
,(12,'Alan',2)
,(13,'Peter',3)
,(14,'Sherry',4)
,(15,'Howard',5)
,(16,'Barry',5)
,(17,'Jeanine',4)
,(18,'Andrew',4)
,(19,'Peter',4)
,(20,'Robert',1)
,(21,'Jennifer',3);
-- DDL and sample data population, end
SELECT e.*, s.A_FNAME AS Supervisor
FROM #AGENT AS e INNER JOIN
#AGENT AS s ON s.A_CODE = e.S_CODE;
Output
+--------+-----------+--------+------------+
| A_CODE | A_FNAME | S_CODE | Supervisor |
+--------+-----------+--------+------------+
| 1 | John | 1 | John |
| 2 | Nancy | 1 | John |
| 3 | Lottie | 2 | Nancy |
| 4 | Jennie | 1 | John |
| 5 | Robert | 3 | Lottie |
| 6 | Cary | 1 | John |
| 7 | Roberto | 3 | Lottie |
| 8 | Elizabeth | 1 | John |
| 9 | Jack | 2 | Nancy |
| 10 | Rose | 4 | Jennie |
| 11 | Tom | 3 | Lottie |
| 12 | Alan | 2 | Nancy |
| 13 | Peter | 3 | Lottie |
| 14 | Sherry | 4 | Jennie |
| 15 | Howard | 5 | Robert |
| 16 | Barry | 5 | Robert |
| 17 | Jeanine | 4 | Jennie |
| 18 | Andrew | 4 | Jennie |
| 19 | Peter | 4 | Jennie |
| 20 | Robert | 1 | John |
| 21 | Jennifer | 3 | Lottie |
+--------+-----------+--------+------------+
Related
The concerned tables are as follows:
students(rollno, name, deptcode)
depts(deptcode, deptname)
course(crs_rollno, crs_name, marks)
The query is
Find the name and roll number of the students from each department who obtained
highest total marks in their own department.
Consider:
i) Courses of different department are different.
ii) All students of a particular department take same number and same courses.
Then only the query makes sense.
I wrote a successful query for displaying the maximum total marks by a student in each department.
select do.deptname, max(x.marks) from students so
inner join depts do
on do.deptcode=so.deptcode
inner join(
select s.name as name, d.deptname as deptname, sum(c.marks) as marks from students s
inner join crs_regd c
on s.rollno=c.crs_rollno
inner join depts d
on d.deptcode=s.deptcode
group by s.name,d.deptname) x
on x.name=so.name and x.deptname=do.deptname group by do.deptname;
But as mentioned I need to display the name as well. Accordingly if I include so.name in select list, I need to include it in group by clause and the output is as below:
Kendra Summers Computer Science 274
Stewart Robbins English 80
Cole Page Computer Science 250
Brian Steele English 83
expected output:
Kendra Summers Computer Science 274
Brian Steele English 83
Where is the problem?
I guess this can be easily achieved if you use window function -
select name, deptname, marks
from (select s.name as name, d.deptname as deptname, sum(c.marks) as marks,
row_number() over(partition by d.deptname order by sum(c.marks) desc) rn
from students s
inner join crs_regd c on s.rollno=c.crs_rollno
inner join depts d on d.deptcode=s.deptcode
group by s.name,d.deptname) x
where rn = 1;
To solve the problem with a readable query I had to define a couple of views:
total_marks: For each student the sum of their marks
create view total_marks as select s.deptcode, s.name, s.rollno, sum(c.marks) as total from course c, students s where s.rollno = c.crs_rollno group by s.rollno;
dept_max: For each department the highest total score by a single student of that department
create view dept_max as select deptcode, max(total) max_total from total_marks group by deptcode;
So I can get the desidered output with the query
select a.deptcode, a.rollno, a.name from total_marks a join dept_max b on a.deptcode = b.deptcode and a.total = b.max_total
If you don't want to use views you can replace their selects on the final query, which will result in this:
select a.deptcode, a.rollno, a.name
from
(select s.deptcode, s.name, s.rollno, sum(c.marks) as total from course c, students s where s.rollno = c.crs_rollno group by s.rollno) a
join (select deptcode, max(total) max_total from (select s.deptcode, s.name, s.rollno, sum(c.marks) as total from course c, students s where s.rollno = c.crs_rollno group by s.rollno) a_ group by deptcode) b
on a.deptcode = b.deptcode and a.total = b.max_total
Which I'm sure it is easily improvable in performance by someone more skilled then me...
If you (and anybody else) want to try it the way I did, here is the schema:
create table depts ( deptcode int primary key auto_increment, deptname varchar(20) );
create table students ( rollno int primary key auto_increment, name varchar(20) not null, deptcode int, foreign key (deptcode) references depts(deptcode) );
create table course ( crs_rollno int, crs_name varchar(20), marks int, foreign key (crs_rollno) references students(rollno) );
And here all the entries I inserted:
insert into depts (deptname) values ("Computer Science"),("Biology"),("Fine Arts");
insert into students (name,deptcode) values ("Turing",1),("Jobs",1),("Tanenbaum",1),("Darwin",2),("Mendel",2),("Bernard",2),("Picasso",3),("Monet",3),("Van Gogh",3);
insert into course (crs_rollno,crs_name,marks) values
(1,"Algorithms",25),(1,"Database",28),(1,"Programming",29),(1,"Calculus",30),
(2,"Algorithms",24),(2,"Database",22),(2,"Programming",28),(2,"Calculus",19),
(3,"Algorithms",21),(3,"Database",27),(3,"Programming",23),(3,"Calculus",26),
(4,"Zoology",22),(4,"Botanics",28),(4,"Chemistry",30),(4,"Anatomy",25),(4,"Pharmacology",27),
(5,"Zoology",29),(5,"Botanics",27),(5,"Chemistry",26),(5,"Anatomy",25),(5,"Pharmacology",24),
(6,"Zoology",18),(6,"Botanics",19),(6,"Chemistry",22),(6,"Anatomy",23),(6,"Pharmacology",24),
(7,"Sculpture",26),(7,"History",25),(7,"Painting",30),
(8,"Sculpture",29),(8,"History",24),(8,"Painting",30),
(9,"Sculpture",21),(9,"History",19),(9,"Painting",25) ;
Those inserts will load these data:
select * from depts;
+----------+------------------+
| deptcode | deptname |
+----------+------------------+
| 1 | Computer Science |
| 2 | Biology |
| 3 | Fine Arts |
+----------+------------------+
select * from students;
+--------+-----------+----------+
| rollno | name | deptcode |
+--------+-----------+----------+
| 1 | Turing | 1 |
| 2 | Jobs | 1 |
| 3 | Tanenbaum | 1 |
| 4 | Darwin | 2 |
| 5 | Mendel | 2 |
| 6 | Bernard | 2 |
| 7 | Picasso | 3 |
| 8 | Monet | 3 |
| 9 | Van Gogh | 3 |
+--------+-----------+----------+
select * from course;
+------------+--------------+-------+
| crs_rollno | crs_name | marks |
+------------+--------------+-------+
| 1 | Algorithms | 25 |
| 1 | Database | 28 |
| 1 | Programming | 29 |
| 1 | Calculus | 30 |
| 2 | Algorithms | 24 |
| 2 | Database | 22 |
| 2 | Programming | 28 |
| 2 | Calculus | 19 |
| 3 | Algorithms | 21 |
| 3 | Database | 27 |
| 3 | Programming | 23 |
| 3 | Calculus | 26 |
| 4 | Zoology | 22 |
| 4 | Botanics | 28 |
| 4 | Chemistry | 30 |
| 4 | Anatomy | 25 |
| 4 | Pharmacology | 27 |
| 5 | Zoology | 29 |
| 5 | Botanics | 27 |
| 5 | Chemistry | 26 |
| 5 | Anatomy | 25 |
| 5 | Pharmacology | 24 |
| 6 | Zoology | 18 |
| 6 | Botanics | 19 |
| 6 | Chemistry | 22 |
| 6 | Anatomy | 23 |
| 6 | Pharmacology | 24 |
| 7 | Sculpture | 26 |
| 7 | History | 25 |
| 7 | Painting | 30 |
| 8 | Sculpture | 29 |
| 8 | History | 24 |
| 8 | Painting | 30 |
| 9 | Sculpture | 21 |
| 9 | History | 19 |
| 9 | Painting | 25 |
+------------+--------------+-------+
I take chance to point out that this database is badly designed. This becomes evident with course table. For these reasons:
The name is singular
This table does not represent courses, but rather exams or scores
crs_name should be a foreign key referencing the primary key of another table (that would actually represent the courses)
There is no constrains to limit the marks to a range and to avoid a student to take twice the same exam
I find more logical to associate courses to departments, instead of student to departments (this way also would make these queries easier)
I tell you this because I understood you are learning from a book, so unless the book at one point says "this database is poorly designed", do not take this exercise as example to design your own!
Anyway, if you manually resolve the query with my data you will come to this results:
+----------+--------+---------+
| deptcode | rollno | name |
+----------+--------+---------+
| 1 | 1 | Turing |
| 2 | 6 | Bernard |
| 3 | 8 | Monet |
+----------+--------+---------+
As further reference, here the contents of the views I needed to define:
select * from total_marks;
+----------+-----------+--------+-------+
| deptcode | name | rollno | total |
+----------+-----------+--------+-------+
| 1 | Turing | 1 | 112 |
| 1 | Jobs | 2 | 93 |
| 1 | Tanenbaum | 3 | 97 |
| 2 | Darwin | 4 | 132 |
| 2 | Mendel | 5 | 131 |
| 2 | Bernard | 6 | 136 |
| 3 | Picasso | 7 | 81 |
| 3 | Monet | 8 | 83 |
| 3 | Van Gogh | 9 | 65 |
+----------+-----------+--------+-------+
select * from dept_max;
+----------+-----------+
| deptcode | max_total |
+----------+-----------+
| 1 | 112 |
| 2 | 136 |
| 3 | 83 |
+----------+-----------+
Hope I helped!
Try the following query
select a.name, b.deptname,c.marks
from students a
, crs_regd b
, depts c
where a.rollno = b.crs_rollno
and a.deptcode = c.deptcode
and(c.deptname,b.marks) in (select do.deptname, max(x.marks)
from students so
inner join depts do
on do.deptcode=so.deptcode
inner join (select s.name as name
, d.deptname as deptname
, sum(c.marks) as marks
from students s
inner join crs_regd c
on s.rollno=c.crs_rollno
inner join depts d
on d.deptcode=s.deptcode
group by s.name,d.deptname) x
on x.name=so.name
and x.deptname=do.deptname
group by do.deptname
)
Inner/Sub query will fetch the course name and max marks and the outer query gets the corresponding name of the student.
try and let know if you got the desired result
Dense_Rank() function would be helpful in this scenario:
SELECT subquery.*
FROM (SELECT Student_Total_Marks.rollno,
Student_Total_Marks.name,
Student_Total_Marks.deptcode, depts.deptname,
rank() over (partition by deptcode order by total_marks desc) Student_Rank
FROM (SELECT Stud.rollno,
Stud.name,
Stud.deptcode,
sum(course.marks) total_marks
FROM students stud inner join course course on stud.rollno = course.crs_rollno
GROUP BY stud.rollno,Stud.name,Stud.deptcode) Student_Total_Marks,
dept dept
WHERE Student_Total_Marks.deptcode = dept.deptname
GROUP BY Student_Total_Marks.deptcode) subquery
WHERE suquery.student_rank = 1
I have a 1 table in a db that stored Incoming, Outgoing and Net values for various Account Codes over time. Although there is a date field the sequence of events per Account Code is based on the "Version" number where 0 = original record for each Account Code and it increments by 1 after each change to that Account Code.
The Outgoing and Incoming values are stored in the db as cumulative values rather than the individual transaction value but I am looking for a way to Select * From this table and return the individual amounts as opposed to the cumulative.
Below are test scripts of table and data, and also 2 examples.
If i Select where code = '123' in the test table I currently get this (values are cumulative);
+------+------------+---------+---------+---------+-----+
| Code | Date | Version | Incoming| Outgoing| Net |
+------+------------+---------+---------+---------+-----+
| 123 | 01/01/2018 | 0 | 100 | 0 | 100 |
| 123 | 07/01/2018 | 1 | 150 | 0 | 150 |
| 123 | 09/01/2018 | 2 | 150 | 100 | 50 |
| 123 | 14/01/2018 | 3 | 200 | 100 | 100 |
| 123 | 18/01/2018 | 4 | 200 | 175 | 25 |
| 123 | 23/01/2018 | 5 | 225 | 175 | 50 |
| 123 | 30/01/2018 | 6 | 225 | 225 | 0 |
+------+------------+---------+---------+---------+-----+
This is what I would like to see (each individual transaction);
+------+------------+---------+----------+----------+------+
| Code | Date | Version | Incoming | Outgoing | Net |
+------+------------+---------+----------+----------+------+
| 123 | 01/01/2018 | 0 | 100 | 0 | 100 |
| 123 | 07/01/2018 | 1 | 50 | 0 | 50 |
| 123 | 09/01/2018 | 2 | 0 | 100 | -100 |
| 123 | 14/01/2018 | 3 | 50 | 0 | 50 |
| 123 | 18/01/2018 | 4 | 0 | 75 | -75 |
| 123 | 23/01/2018 | 5 | 25 | 0 | 25 |
| 123 | 30/01/2018 | 6 | 0 | 50 | -50 |
+------+------------+---------+----------+----------+------+
If I had the individual transaction values and wanted to report on the cumulative, I would use an OVER PARTITION BY, but is there an opposite to that?
I am not looking to redesign the create table or the process in which it is stored, I am just looking for a way to report on this from our MI environment.
Note: I've added other random Account Codes into this to emphasis how the data is not ordered by Code or Version, but by Date.
thanks in advance for any help.
USE [tempdb];
IF EXISTS ( SELECT *
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_NAME = 'Table1'
AND TABLE_SCHEMA = 'dbo')
DROP TABLE [dbo].[Table1];
GO
CREATE TABLE [dbo].[Table1]
(
[Code] CHAR(3)
,[Date] DATE
,[Version] CHAR(3)
,[Incoming] DECIMAL(20,2)
,[Outgoing] DECIMAL(20,2)
,[Net] DECIMAL(20,2)
);
GO
INSERT INTO [dbo].[Table1] VALUES
('123','2018-01-01','0','100','0','100'),
('456','2018-01-02','0','50','0','50'),
('789','2018-01-03','0','0','0','0'),
('456','2018-01-04','1','100','0','100'),
('456','2018-01-05','2','150','0','150'),
('789','2018-01-06','1','50','50','0'),
('123','2018-01-07','1','150','0','150'),
('456','2018-01-08','3','200','0','200'),
('123','2018-01-09','2','150','100','50'),
('789','2018-01-10','2','0','0','0'),
('456','2018-01-11','4','225','0','225'),
('789','2018-01-12','3','75','25','50'),
('987','2018-01-13','0','0','50','-50'),
('123','2018-01-14','3','200','100','100'),
('654','2018-01-15','0','100','0','100'),
('456','2018-01-16','5','250','0','250'),
('987','2018-01-17','1','50','50','0'),
('123','2018-01-18','4','200','175','25'),
('789','2018-01-19','4','100','25','75'),
('987','2018-01-20','2','150','125','25'),
('321','2018-01-21','0','100','0','100'),
('654','2018-01-22','1','0','0','0'),
('123','2018-01-23','5','225','175','50'),
('321','2018-01-24','1','100','50','50'),
('789','2018-01-25','5','100','50','50'),
('987','2018-01-26','3','150','150','0'),
('456','2018-01-27','6','250','250','0'),
('456','2018-01-28','7','270','250','20'),
('321','2018-01-29','2','100','100','0'),
('123','2018-01-30','6','225','225','0'),
('987','2018-01-31','4','175','150','25')
;
GO
SELECT *
FROM [dbo].[Table1]
WHERE [Code] = '123'
GO;
USE [tempdb];
IF EXISTS ( SELECT *
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_NAME = 'Table1'
AND TABLE_SCHEMA = 'dbo')
DROP TABLE [dbo].[Table1];
GO;
}
Just use lag():
select Evt, Date, Version,
(Loss - lag(Loss, 1, 0) over (partition by evt order by date)) as incoming,
(Rec - lag(Rec, 1, 0) over (partition by evt order by date)) as outgoing,
(Net - lag(Net, 1, 0) over (partition by evt order by date)) as net
from [dbo].[Table1];
I am looking for an output like:
| BOOK | ANALYST | SUPERVISOR |
|-------|----------------|--------------------|
| BookA | (null) | Dani Sant |
| BookB | (null) | North Andre Miles |
| BookC | Andrea Plus | Andrea Plus |
| BookD | Jeff Dron Math | Jeff Dron Math |
| BookE | Theo Phillip | Julian Rhode |
What I am getting is:
| BOOK | ANALYST | SUPERVISOR |
|-------|----------------|--------------|
| BookA | (null) | dani.sant |
| BookB | (null) | north.miles |
| BookC | Andrea Plus | andrea.plus |
| BookD | Jeff Dron Math | jeff.math |
| BookE | Theo Phillip | julian.rhode |
I can do the join with one column, but when I try for both, the result isn't showing like it should. Thanks for any information on this.
SQL Fiddle
MS SQL Server 2008 Schema Setup:
CREATE TABLE books
(
book varchar(10),
analyst varchar(100),
supervisor varchar(100)
);
INSERT INTO books (book, analyst, supervisor)
VALUES
('BookA', NULL, 'dani.sant'),
('BookB', NULL, 'north.miles'),
('BookC', 'andrea.plus', 'andrea.plus'),
('BookD', 'jeff.math', 'jeff.math'),
('BookE', 'theo.phil', 'julian.rhode');
CREATE TABLE names
(
username varchar(100),
fullname varchar(500)
);
INSERT INTO names (username, fullname)
VALUES
('dani.sant', 'Dani Sant'),
('north.miles', 'North Andre Miles'),
('andrea.plus', 'Andrea Plus'),
('jeff.math', 'Jeff Dron Math'),
('theo.phil', 'Theo Phillip'),
('julian.rhode', 'Julian Rhode');
Query 1:
SELECT
books.book AS Book,
names.fullname AS Analyst,
books.supervisor AS Supervisor
FROM
books left join names on books.analyst = names.username
Results:
| BOOK | ANALYST | SUPERVISOR |
|-------|----------------|--------------|
| BookA | (null) | dani.sant |
| BookB | (null) | north.miles |
| BookC | Andrea Plus | andrea.plus |
| BookD | Jeff Dron Math | jeff.math |
| BookE | Theo Phillip | julian.rhode |
You need a second join to the names table to get the supervisor's full name:
SELECT b.book AS Book, bn.fullname AS Analyst,
sn.fullname AS Supervisor
FROM books b left join
names bn
on b.analyst = bn.username left join
names sn
on b.supervisor = sn.username;
Below will provide the output you desire.
SELECT
b.book AS Book,
n.fullname AS Analyst,
(SELECT fullname FROM names where username=b.Supervisor) AS Supervisor
FROM
books b left join names n on b.analyst = n.username
I have a Customer table and an Address table.
The Address table has a flag which is either INVOICE, CORRESPONDENCE or DELIVERY.
A Customer can have 0 to many Address records.
I want to be able to query both tables and generate a flag for each customer based on the address data - no address records = NONE, 1 or more INVOICE records = HASINVOICE, no INVOICE but 1 or more others = HASOTHER
so, for the following data:
+------------+---------+
| CustomerID | Name |
+------------+---------+
| 1 | Peter |
| 2 | Ray |
| 3 | Egon |
| 4 | Winston |
| 5 | Dana |
+------------+---------+
+-----------+------------+----------------+
| AddressID | CustomerID | AddressType |
+-----------+------------+----------------+
| 1 | 1 | INVOICE |
| 2 | 1 | DELIVERY |
| 3 | 2 | DELIVERY |
| 4 | 2 | CORRESPONDENCE |
| 5 | 4 | INVOICE |
| 6 | 5 | CORRESPONDENCE |
+-----------+------------+----------------+
I would expect the following output:
+------------+---------+-------------+
| CustomerID | Name | AddressFlag |
+------------+---------+-------------+
| 1 | Peter | HASINVOICE |
| 2 | Ray | HASOTHER |
| 3 | Egon | NONE |
| 4 | Winston | HASINVOICE |
| 5 | Dana | HASOTHER |
+------------+---------+-------------+
Is this possible, for SQL 2000, using a single query and no cursors?
I don't have a 2000 instance handy (you really should upgrade, you're 4-5 releases behind), but I think that this should work:
declare #Customers table (CustomerID int,Name varchar(10))
insert into #Customers (CustomerID,Name)
select 1,'Peter' union all select 2,'Ray' union all
select 3,'Egon' union all select 4,'Winston' union all
select 5,'Dana'
declare #Addresses table (AddressID int, CustomerID int,
AddressType varchar(30))
insert into #Addresses (AddressID,CustomerID,AddressType)
select 1,1,'INVOICE' union all select 2,1,'DELIVERY' union all
select 3,2,'DELIVERY' union all select 4,2,'CORRESPONDENCE' union all
select 5,4,'INVOICE' union all select 6,5,'CORRESPONDENCE'
select
c.CustomerID,
c.Name,
CASE MAX(CASE
WHEN a.AddressType = 'Invoice' THEN 2
WHEN a.AddressType IS NOT NULL THEN 1
END
) WHEN 2 THEN 'HASINVOICE'
WHEN 1 THEN 'HASOTHER'
ELSE 'NONE'
END as AddressFlag
from
#Customers c
left join
#Addresses a
on
c.CustomerID = a.CustomerID
group by
c.CustomerID,
c.Name
Produces:
CustomerID Name AddressFlag
----------- ---------- -----------
5 Dana HASOTHER
3 Egon NONE
1 Peter HASINVOICE
2 Ray HASOTHER
4 Winston HASINVOICE
Can you please help me build an SQL query to retrieve data from a history table?
I'm a newbie with only a one-week coding experience. I've been trying simple SELECT statements so far but have hit a stumbling block.
My football club's database has three tables. The first one links balls to players:
BallDetail
| BallID | PlayerID | TeamID |
|-------------------|--------|
| 1 | 11 | 21 |
| 2 | 12 | 22 |
The second one lists things that happen to the balls:
BallEventHistory
| BallID | Event | EventDate |
|--------|------ |------------|
| 1 | Pass | 2012-01-01 |
| 1 | Shoot | 2012-02-01 |
| 1 | Miss | 2012-03-01 |
| 2 | Pass | 2012-01-01 |
| 2 | Shoot | 2012-02-01 |
And the third one is a history change table. After a ball changes hands, history is recorded:
HistoryChanges
| BallID | ColumnName | ValueOld | ValueNew |
|--------|------------|----------|----------|
| 2 | PlayerID | 11 | 12 |
| 2 | TeamID | 21 | 22 |
I'm trying to obtain a table that would list all passes and shoots Player 11 had done to all balls before the balls went to other players. Like this:
| PlayerID | BallID | Event | Month |
|----------|--------|-------|-------|
| 11 | 1 | Pass | Jan |
| 11 | 1 | Shoot | Feb |
| 11 | 2 | Pass | Jan |
I begin so:
SELECT PlayerID, BallID, Event, DateName(month, EventDate)
FROM BallDetail bd INNER JOIN BallEventHistory beh ON bd.BallID = beh.BallID
WHERE PlayerID = 11 AND Event IN (Pass, Shoot) ...
But how to make sure that Ball 2 also gets included despite being with another player now?
Select PlayerID,BallID,Event,datename(month,EventDate) as Month,Count(*) as cnt from
(
Select
Coalesce(
(Select ValueNew from #HistoryChanges where ChangeDate=(Select max(ChangeDate) from #HistoryChanges h2 where h2.BallID=h.BallID and ColumnName='PlayerID' and ChangeDate<=EventDate) and BallID=h.BallID and ColumnName='PlayerID')
,(Select PlayerID from #BallDetail where BallID=h.BallID)
) as PlayerID,
h.BallID,h.Event,EventDate
from #BallEventHistory h
) a
Group by PlayerID, BallID, Event,datename(month,EventDate)
SELECT d.PlayerID, d.BallID, h.Event, DATENAME(mm, h.EventDate) AS Month
FROM BallDetail d JOIN BallEventHistory h ON d.BallID = h.BallID
WHERE h.Event IN ('Pass', 'Shoot') AND d.PlayerID = 11
OR EXISTS (SELECT 1
FROM dbo.HistoryChanges c
WHERE c.ValueOld = 11 AND c.ValueNew = d.PlayerID AND c.ColumnName = 'PlayerID' and c.ChangeDate = h.EventDate)