Drop Table
Support Forum for database administrators and web based access to important newsgroups related to databasesI have a table (cars) with 3 fields: VIN, Class, sell_price 101, sports, 10000 102, sports, 11000 103, luxury, 9000 104, sports, 11000 105, sports, 11000 106, luxury, 5000 107, sports, 11000 108, sports, 11000 109, luxury, 9000 i need to write a query that WITHOUT USING A FUNCTION will return the median selling price for each class of car. result should look like: Class, Med_Price luxury, 9000 sports, 11000 thanks to all u SQLers
Post Follow-up to this message>From your sample data it looks like you want the most commonly occurring price for each vehicle (I thought this was called the "mode", not the "median"). CREATE TABLE Cars(VIN INT,Class VARCHAR(10),sell_pri ce INT) INSERT INTO Cars(VIN,Class,sell_ price) VALUES(101, 'sports', 10000) INSERT INTO Cars(VIN,Class,sell_ price) VALUES(102, 'sports', 11000) INSERT INTO Cars(VIN,Class,sell_ price) VALUES(103, 'luxury', 9000) INSERT INTO Cars(VIN,Class,sell_ price) VALUES(104, 'sports', 11000) INSERT INTO Cars(VIN,Class,sell_ price) VALUES(105, 'sports', 11000) INSERT INTO Cars(VIN,Class,sell_ price) VALUES(106, 'luxury', 5000) INSERT INTO Cars(VIN,Class,sell_ price) VALUES(107, 'sports', 11000) INSERT INTO Cars(VIN,Class,sell_ price) VALUES(108, 'sports', 11000) INSERT INTO Cars(VIN,Class,sell_ price) VALUES(109, 'luxury', 9000) GO CREATE VIEW CarNums AS SELECT Class,sell_price,COU NT(*) as Num FROM Cars GROUP BY Class,sell_price GO SELECT c1.Class,c1.sell_price AS Med_Price FROM CarNums c1 INNER JOIN ( SELECT Class,MAX(Num) FROM CarNums GROUP BY Class) C2(Class,Num) ON C2.Class=C1.Class AND C2.Num=C1.Num
Post Follow-up to this messageMy mistake, you can get the medians using this CREATE VIEW CarRank AS SELECT c1.VIN, c1.Class, c1.sell_price, (SELECT COUNT(*) FROM Cars c2 WHERE c2.Class=c1.Class AND ((c2.sell_price<c1.sell_price) OR (c2.sell_price=c1.sell_price AND c2.VIN<=c1.VIN))) as Rank, (SELECT COUNT(*) FROM Cars c2 WHERE c2.Class=c1.Class) as MaxRank FROM Cars c1 GO SELECT Class,AVG(sell_price ) AS Med_Price FROM CarRank WHERE Rank IN ((MaxRank+1)/2,(MaxRank/2)+1) GROUP BY Class
Post Follow-up to this messageI have a whoel chapter on verious ways to do this in SQL FOR SMARTIES. Here is one answer. Median with Characteristic Function Anatoly Abramovich, Yelena Alexandrova, and Eugene Birger presented a series of articles in SQL Forum magazine on computing the median (SQL Forum 1993, 1994). They define a characteristic function, which they call delta, using the Sybase sign() function. The delta or characteristic function accepts a Boolean expression as an argument and returns a 1 if it is TRUE and a zero if it is FALSE or UNKNOWN. In SQL-92 we have a CASE expression, which can be used to construct the delta function. This is new to SQL-92, but you can find vendor functions of the form IF...THEN...ELSE that behave like the condition expression in Algol or like the question markPcolon operator in C. The authors also distinguish between the statistical median, whose value must be a member of the set, and the financial median, whose value is the average of the middle two members of the set. A statistical median exists when there is an odd number of items in the set. If there is an even number of items, you must decide if you want to use the highest value in the lower half (they call this the left median) or the lowest value in the upper half (they call this the right median). The left statistical median of a unique column can be found with this query: SELECT P1.bin FROM Parts AS P1, Parts AS P2 GROUP BY P1.bin HAVING SUM(CASE WHEN (P2.bin <= P1.bin) THEN 1 ELSE 0 END) = (COUNT(*) + 1) / 2; Changing the direction of the theta test in the HAVING clause will allow you to pick the right statistical median if a central element does not exist in the set. You will also notice something else about the median of a set of unique values: It is usually meaningless. What does the median bin number mean, anyway? A good rule of thumb is that if it does not make sense as an average, it does not make sense as a median. The statistical median of a column with duplicate values can be found with a query based on the same ideas, but you have to adjust the HAVING clause to allow for overlap; thus, the left statistical median is found by SELECT P1.weight FROM Parts AS P1, Parts AS P2 GROUP BY P1.weight HAVING SUM(CASE WHEN P2.weight <= P1.weight THEN 1 ELSE 0 END) >= ((COUNT(*) + 1) / 2) AND SUM(CASE WHEN P2.weight >= P1.weight THEN 1 ELSE 0 END) >= (COUNT(*)/2 + 1); Notice that here the left and right medians can be the same, so there is no need to pick one over the other in many of the situations where you have an even number of items. Switching the comparison operators in the two CASE expressions will give you the right statistical median. The author's query for the financial median depends on some Sybase features that cannot be found in other products, so I would recommend using a combination of the right and left statistical medians to return a set of values about the center of the data, and then averaging them, thus: SELECT AVG(P1.weight) FROM Parts AS P1, Parts AS P2 HAVING (SUM(CASE WHEN P2.weight <= P1.weight -- left median THEN 1 ELSE 0 END) >= ((COUNT(*) + 1) / 2) AND SUM(CASE WHEN P2.weight >= P1.weight THEN 1 ELSE 0 END) >= (COUNT(*)/2 + 1)) OR (SUM(CASE WHEN P2.weight >= P1.weight -- right median THEN 1 ELSE 0 END) >= ((COUNT(*) + 1) / 2) AND SUM(CASE WHEN P2.weight <= P1.weight THEN 1 ELSE 0 END) >= (COUNT(*)/2 + 1)); An optimizer may be able to reduce this expression internally, since the expressions involved with COUNT(*) are constants. This entire query could be put into a FROM clause and the average taken of the one or two rows in the result to find the financial median. In SQL-89, you would have to define this as a VIEW and then take the average. If you have SQL-2005, you can try something like (untested): SELECT AVG(x), ROW_NUMBER () OVER (ORDER BY x ASC) AS hi, ROW_NUMBER () OVER (ORDER BY x DESC) AS lo, FROM Foobar WHERE hi IN (lo, lo-1, lo+1);
Post Follow-up to this messagei don't do homework for college students.
Post Follow-up to this message
Show a Printable Version
Email This Page to Someone!
Receive updates to this thread