Groups | Blog | Home
all groups > sql server programming > january 2004 >

sql server programming : Compare one period to another


nOID
1/8/2004 11:41:05 PM
I have tables named: Name, Date, Income , with the following columns and 2 inner joins from the Income table to each of the other tables via the lookup columns(they are more complicated, but this illustrates the basic layout).

Name
A
B

Date
2003_Q1
2003_Q2
2003_Q3
2003_Q4
2004_Q1
2004_Q2
2004_Q3
2004_Q4

Income ,Name Lookup, Date Lookup
12 ,A,2003_Q1
13 ,A,2003_Q2
11 ,A,2003_Q3
12 ,A,2003_Q4
11 ,B,2004_Q1
13 ,B,2004_Q2
14 ,B,2004_Q3
15 ,B,2004_Q4

The query criteria is to be:

Income for Q3_2003 > Income for Q2_2003 > Income for Q1_2003

I want to return a list of Names that match the Income criteria above, ie q3>q2>q1. In my example above, only Name B would be returned.

How should this be written?

Thanks,

nOID
David Portas
1/9/2004 8:19:45 AM
Put the year and quarter in separate columns in the Income table. The design
you've given looks more like an OLAP star schema. In a relational design
columns should be atomic. Your task is much easier if you fix this first.

CREATE TABLE Name (iname CHAR(1) PRIMARY KEY, name VARCHAR(10) NOT NULL
UNIQUE)

CREATE TABLE Income (income INTEGER, iname CHAR(1) REFERENCES Name (iname),
iyear INTEGER CHECK (iyear BETWEEN 1990 AND 2100), iquarter INTEGER CHECK
(iquarter BETWEEN 1 AND 4), PRIMARY KEY (iname, iyear, iquarter))

INSERT INTO Name VALUES ('A','Name A')
INSERT INTO Name VALUES ('B','Name B')

INSERT INTO Income VALUES (12 ,'A', 2003, 1)
INSERT INTO Income VALUES (13 ,'A', 2003, 2)
INSERT INTO Income VALUES (11 ,'A', 2003, 3)
INSERT INTO Income VALUES (12 ,'A', 2003, 4)
INSERT INTO Income VALUES (11 ,'B', 2004, 1)
INSERT INTO Income VALUES (13 ,'B', 2004, 2)
INSERT INTO Income VALUES (14 ,'B', 2004, 3)
INSERT INTO Income VALUES (15 ,'B', 2004, 4)

SELECT income, N.name, iyear, iquarter
FROM Income AS I
JOIN Name AS N
ON I.iname = N.iname
WHERE iquarter BETWEEN 1 AND 3
AND NOT EXISTS
(SELECT *
FROM Income AS I1
JOIN Income AS I2
ON I1.iname = I2.iname
AND I1.iyear = I2.iyear
AND I1.iquarter = I2.iquarter-1
AND I2.iquarter BETWEEN 2 AND 3
AND I1.income >= I2.income
WHERE I1.iname = I.iname)

You can easily adjust this to cover whatever periods you require by changing
the BETWEEN predicates.

--
David Portas
------------
Please reply only to the newsgroup
--

David Portas
1/9/2004 8:29:01 AM
Oops. Last line should read:

WHERE I1.iname = I.iname AND I1.iyear = I.iyear)

--
David Portas
------------
Please reply only to the newsgroup
--

Joe Celko
1/9/2004 11:21:28 AM
How about this version?

SELECT N1.name
FROM Names AS N1, Incomes AS I1, Incomes AS I2, Incomes AS I3
WHERE N1.iname = I1.iname
AND I1.iquarter = 1
AND I2.iquarter = 2
AND I3.iquarter = 3
AND I1.iyear = I2.iyear
AND I1.iyear = I3.iyear
AND I2.income BETWEEN I1.income AND I3.income
AND I2.income NOT IN (I1.income, I3.income);

--CELKO--
===========================
Please post DDL, so that people do not have to guess what the keys,
constraints, Declarative Referential Integrity, datatypes, etc. in your
schema are.

*** Sent via Developersdex http://www.developersdex.com ***
Steve Kass
1/9/2004 5:48:55 PM


[quoted text, click to view]
I think the original question wanted the income condition to be true
about a single person. This returns a name whenever there was any q2
salary greater than that person's q1 salary and any q3 salary greater
than that q2 salary, even all three salaries come from different people.

SK

[quoted text, click to view]
David Portas
1/9/2004 8:22:52 PM
You only asked for the Name so you can use a slightly simpler query than my
original:

SELECT name
FROM Name AS N
WHERE
(SELECT COUNT(*)
FROM Income AS I1
JOIN Income AS I2
ON I1.iname = N.iname
AND I2.iname = N.iname
AND I1.iyear = I2.iyear
AND I1.iquarter = I2.iquarter-1
AND I2.iquarter BETWEEN 2 AND 3
AND I1.income < I2.income)=2

--
David Portas
------------
Please reply only to the newsgroup
--

v nOID
1/9/2004 11:56:10 PM
ok, this is what I have come up with and it seems to work after a little testing. I can't really say that I understand much of this, except that the query for the compare appears to rely upon the data table being joined to itself so that it can compare one time period to another...does that sound about right?

I hope you all don't mind if I have more questions about this, going forward 'cause I suspect that I will.

Thanks to all for all the help, v nOID


CREATE TABLE Name_Symbol (dsymbol CHAR(10) PRIMARY KEY, name VARCHAR(30) NOT NULL UNIQUE)

CREATE TABLE Industry (dindustry CHAR(30) PRIMARY KEY)

CREATE TABLE Sector (dsector CHAR(30) PRIMARY KEY)

CREATE TABLE Hyperlinks (dyahoo_main CHAR(100) PRIMARY KEY, yahoo_main VARCHAR (100) , msn_10Qs VARCHAR(100) NOT NULL UNIQUE, msn_events VARCHAR(100) NOT NULL UNIQUE, multex_events VARCHAR(100) NOT NULL UNIQUE)

CREATE TABLE Data_03 (cash INTEGER, cash_flow INTEGER, cash_ratio DECIMAL, current_assets INTEGER, current_liabilities INTEGER, debt_long_term INTEGER, dso INTEGER, eps DECIMAL, income INTEGER, inventories INTEGER, margin_net DECIMAL, margin_net_con_ops DECIMAL, margin_operating DECIMAL, pe INTEGER, ps DECIMAL, quick_ratio DECIMAL, revenue INTEGER, roa INTEGER, roe INTEGER, roic INTEGER, shares_out INTEGER, tax_rate DECIMAL,
dsymbol CHAR(10) REFERENCES Name_Symbol (dsymbol),
dyear INTEGER CHECK (dyear BETWEEN 1990 AND 2100),
dquarter INTEGER CHECK(dquarter BETWEEN 1 AND 4),
PRIMARY KEY (dsymbol, dyear, dquarter))

INSERT INTO Name_Symbol VALUES ('A', 'Agilent')
INSERT INTO Name_Symbol VALUES ('B', 'Brillo')

INSERT INTO Industry VALUES ('Semiconductors')
INSERT INTO Industry VALUES ('Advertising')

INSERT INTO Sector VALUES ('Technology')
INSERT INTO Sector VALUES ('Cyclicals')

INSERT INTO Hyperlinks VALUES ('http://www.yahoo.com/A', 'http://www.yahoo.com/A', 'http://www.microsoft.com/A', 'http://www.microsoft.com/A', 'http://www. multex.com/A')
INSERT INTO Hyperlinks VALUES ('http://www.yahoo.com/B', 'http://www.yahoo.com/B', 'http://www.microsoft.com/B', 'http://www.microsoft.com/B', 'http://www.multex.com/B')

INSERT INTO Data_03 VALUES (12 ,45,1.2,34,57,45,35,0.78,45,567,4.5,3.4,56,7,8.9,1.5,200,34,26,32,617,3.4,'A', 2003, 1)
INSERT INTO Data_03 VALUES (13 ,55,1.2,34,57,45,35,0.78,45,567,4.5,3.4,56,7,8.9,1.5,700,34,26,32,617,3.4,'A', 2003, 2)
INSERT INTO Data_03 VALUES (11 ,25,1.2,34,57,45,35,0.78,45,267,4.5,3.4,56,7,6.9,2.5,600,34,66,32,817,6.4,'A', 2003, 3)
INSERT INTO Data_03 VALUES (12 ,45,1.2,34,27,65,25,0.78,65,567,4.5,3.4,66,7,8.9,1.5,700,34,26,32,617,3.8,'A', 2003, 4)
INSERT INTO Data_03 VALUES (13 ,55,1.2,34,57,45,35,0.78,45,267,2.5,3.4,56,7,8.9,1.5,700,34,26,32,817,3.4,'B', 2004, 1)
INSERT INTO Data_03 VALUES (14 ,45,1.2,34,57,45,35,0.78,45,567,4.5,3.4,56,7,8.9,2.5,600,34,66,32,617,6.4,'B', 2004, 2)
INSERT INTO Data_03 VALUES (17 ,65,1.2,34,57,65,35,0.78,45,567,2.5,3.4,66,7,6.9,1.5,700,34,26,32,617,3.4,'B', 2004, 3)
INSERT INTO Data_03 VALUES (12 ,45,1.2,34,27,45,25,0.78,25,267,4.5,3.4,56,7,8.9,2.5,200,34,26,32,617,3.8,'B', 2004, 4)

SELECT cash, N.name, dyear, dquarter
FROM Data_03 AS D
JOIN Name_Symbol AS N
ON D.dsymbol = N.dsymbol
WHERE dquarter BETWEEN 1 AND 3
AND NOT EXISTS
(SELECT *
FROM Data_03 AS D1
JOIN Data_03 AS D2
ON D1.dsymbol = D2.dsymbol
AND D1.dyear = D2.dyear
AND D1.dquarter = D2.dquarter-1
AND D2.dquarter BETWEEN 2 AND 3
AND D1.cash >= D2.cash
AddThis Social Bookmark Button