SQL to get different values into 1 row - sql

I have the following table structure:
VEH_GRP VEH_CODE_IND CATEGORY DATE Mileage_1 Mileage_2
1 A CAR 31-May-08 10
1 B CAR 31-May-08 100
How can I use a sql query to combine them into 1 row? Ideally I would want to perform computation to divide Mileage_1 over Mileage_2..
Thanks everyone.

You would need to use a self join to combine two rows based on some criteria like which 2 rows you require to be combined.
Example :
select
t1.*,t2.* ,t1.mileage_1/t2.mileage_2
from
data_table t1
inner join
data_table t2
on
t1.veh_grp = t2.veh_grp
Also, you'll need to think of some logic to select which row should represent t1 and which should represent t2.

You can use aggregation. I'm not quite sure what the results would look like but:
select VEH_GRP, CATEGORY, DATE,
SUM(Mileage_1), SUM(Mileage_2),
SUM(Mileage_1) / SUM(Mileage_2)
from t
group by VEH_GRP, CATEGORY, DATE;

Related

Select the max value on a multiple table join

I am trying to get the maximum date out of multiple tables when those table have a particular geometry.
My tables more or less look like that (of course they're all different but I shortened them in order to make it clearer ):
A table type :
Id, Info, Geometry, Date
And finally I have an other table that looks like that (shortened again) :
B table:
Id, Geometry
Now, what I want to do is to join all my A type tables on Geometry where they intersect with the B table Geometry, and to get the A table that has the most recent date.
I currently have the following request which is working:
UPDATE last_updateT SET date_last_update= S.dateMax
FROM
(SELECT B.gid, MAX(A.last_date) AS dateMax
FROM B
JOIN A ON ST_Intersects(B.geometry, A.geometry)
GROUP BY B.gid) S
WHERE T.id = S.gid;
Now I'd like to be able to do that kind of join on multiple table that looks like table A. I've heard of the function GREATEST but I am not sure about how to use it.
Also, I use Postgresql if that makes any differences.
It seems you are looking for UNION ALL, so you can treat the data from different tables as if it were data from only one table:
SELECT
b.gid,
MAX(x.last_date) AS dateMax
FROM b
JOIN
(
SELECT geometry, last_date FROM a
UNION ALL
SELECT geometry, last_date FROM aa
UNION ALL
SELECT geometry, last_date FROM aaa
) x ON ST_Intersects(b.geometry, x.geometry)
GROUP BY b.gid;
In broad strokes, MAX is an aggregate function, so you use MAX to get the highest value from the same column over a number of different rows.
GREATEST is a scalar function, you use GREATEST to get the highest value from different columns in the same row.
eg:
SELECT GREATEST(col1,col2,col3)
Greatest: https://www.postgresql.org/docs/9.5/static/functions-conditional.html
Max: https://www.postgresql.org/docs/9.5/static/functions-aggregate.html

Combining the results of two SQL queries as separate columns

I have two queries which return separate result sets, and the queries are returning the correct output.
How can I combine these two queries into one so that I can get one single result set with each result in a separate column?
Query 1:
SELECT SUM(Fdays) AS fDaysSum From tblFieldDays WHERE tblFieldDays.NameCode=35 AND tblFieldDays.WeekEnding=?
Query 2:
SELECT SUM(CHdays) AS hrsSum From tblChargeHours WHERE tblChargeHours.NameCode=35 AND tblChargeHours.WeekEnding=?
Thanks.
You can aliasing both query and Selecting them in the select query
http://sqlfiddle.com/#!2/ca27b/1
SELECT x.a, y.b FROM (SELECT * from a) as x, (SELECT * FROM b) as y
You can use a CROSS JOIN:
SELECT *
FROM ( SELECT SUM(Fdays) AS fDaysSum
FROM tblFieldDays
WHERE tblFieldDays.NameCode=35
AND tblFieldDays.WeekEnding=1) A -- use you real query here
CROSS JOIN (SELECT SUM(CHdays) AS hrsSum
FROM tblChargeHours
WHERE tblChargeHours.NameCode=35
AND tblChargeHours.WeekEnding=1) B -- use you real query here
You could also use a CTE to grab groups of information you want and join them together, if you wanted them in the same row. Example, depending on which SQL syntax you use, here:
WITH group1 AS (
SELECT testA
FROM tableA
),
group2 AS (
SELECT testB
FROM tableB
)
SELECT *
FROM group1
JOIN group2 ON group1.testA = group2.testB --your choice of join
;
You decide what kind of JOIN you want based on the data you are pulling, and make sure to have the same fields in the groups you are getting information from in order to put it all into a single row. If you have multiple columns, make sure to name them all properly so you know which is which. Also, for performance sake, CTE's are the way to go, instead of inline SELECT's and such. Hope this helps.
how to club the 4 query's as a single query
show below query
total number of cases pending + 2.cases filed during this month ( base on sysdate) + total number of cases (1+2) + no. cases disposed where nse= disposed + no. of cases pending (other than nse <> disposed)
nsc = nature of case
report is taken on 06th of every month
( monthly report will be counted from 05th previous month to 05th present of present month)

SQL Delete low counts

I have a table with this data:
Id Qty
-- ---
A 1
A 2
A 3
B 112
B 125
B 109
But I'm supposed to only have the max values for each id. Max value for A is 3 and for B is 125. How can I isolate (and delete) the other values?
The final table should look like this :
Id Qty
-- ---
A 3
B 125
Running MySQL 4.1
Oh wait. Got a simpler solution :
I'll select all the max values(group by id), export the data, flush the table, reimport only the max values.
CREATE TABLE tabletemp LIKE table;
INSERT INTO tabletemp SELECT id,MAX(qty) FROM table GROUP BY id;
DROP TABLE table;
RENAME TABLE tabletemp TO table;
Thanks to all !
Try this in SQL Server:
delete from tbl o
left outer join
(Select max(qty) anz , id
from tbl i
group by i.id) k on o.id = k.id and k.anz = o.qty
where k.id is null
Revision 2 for MySQL... Can anyone check this one?:
delete from tbl o
where concat(id,qty) not in
(select concat(id,anz) from (Select max(qty) anz , id
from tbl i
group by i.id))
Explanation:
Since I was supposed to not use joins (See comments about MySQL Support on joins and delete/update/insert), I moved the subquery into a IN(a,b,c) clause.
Inside an In clause I can use a subquery, but that query is only allowed to return one field. So in order to filter all elements that are not the maximum, i need to concat both fields into a single one, so i can return it inside the in clause. So basically my query inside the IN returns the biggest ID+QTY only. To compare it with the main table i also need to make a concat on the outside, so the data for both fields match.
Basically the In clause contains:
("A3","B125")
Disclaimer: The above query is "evil!" since it uses a function (concat) on fields to compare against. This will cause any index on those fields to become almost useless. You should never formulate a query that way that is run on a regular basis. I only wanted to try to bend it so it works on mysql.
Example of this "bad construct":
(Get all o from the last 2 weeks)
select ... from orders where orderday + 14 > now()
You should allways do:
select ... from orders where orderday > now() - 14
The difference is subtle: Version 2 only has to do the math once, and is able to use the index, and version 1 has to do the math for every single row in the orders table., and you can forget about the index usage...
I'd try this:
delete from T
where exists (
select * from T as T2
where T2.Id = T.Id
and T2.Qty > T.Qty
);
For those who might have similar question in the future, this might be supported some day (it is now in SQL Server 2005 and later)
It won't require a join, and it has advantages over the use of a temporary table if the table has dependencies
with Tranked(Id,Qty,rk) as (
select
Id, Qty,
rank() over (
partition by Id
order by Qty desc
)
from T
)
delete from Tranked
where rk > 1;
You'll have to go via another table (among other things that makes a single delete statement here quite impossible in mysql is you can't delete from a table and use the same table in a subquery).
BEGIN;
create temporary table tmp_del select id,max(qty) as qty from the_tbl;
delete the_tbl from the_tbl,tmp_del where
the_tbl.id=tmp_del.id and the_tbl.qty=tmp_del.qty;
drop table tmp_del;
END;
MySQL 4.0 and later supports a simple multi-table syntax for DELETE:
DELETE t1 FROM MyTable t1 JOIN MyTable t2 ON t1.id = t2.id AND t1.qty < t2.qty;
This produces a join of each row with a given id to all other rows with the same id, and deletes only the row with the lesser qty in each pairing. After this is all done, the row with the greatest qty per group of id is left not deleted.
If you only have one row with a given id, it still works because a single row is naturally the one with the greatest value.
FWIW, I just tried my solution using MySQL 5.0.75 on a Macbook Pro 2.40GHz. I inserted 1 million rows of synthetic data, with different numbers of rows per "group":
2 rows per id completes in 26.78 sec.
5 rows per id completes in 43.18 sec.
10 rows per id completes in 1 min 3.77 sec.
100 rows per id completes in 6 min 46.60 sec.
1000 rows per id didn't complete before I terminated it.

How do I join to a "fixed vector" in SQL?

By "fixed vector" I mean a static list of values, like 1 through 24.
The current query looks like this (simplified)
SELECT Period, Profit FROM Projections
But the data is "sparse" — so there's not a row for every period.
What query will give me a row for peiods 1-24 every time, with zeros (or NULLs) where there's no data?
I would like to do this with just the query to avoid a mess of client code.
Thanks!
You could make a udf called udfRange(start int,count int) or something like that, and left-join to the output of the function.
Or for something really quick and dirty, you could join to a subselect that looked like
SELECT DATA.Period, P.Profit
FROM (
SELECT 1 AS Period
UNION SELECT 2
...
UNION SELECT 24) AS DATA
LEFT JOIN Projections P ON DATA.Period = P.Period
Why not create a 'Periods' lookup table, with values 1 - 24 (and any other columns that might be relevant, like a description of the period, or its name) then do a left outer join between the Periods lookup table and your projections table.

Returning more than one value from a sql statement

I was looking at sql inner queries (bit like the sql equivalent of a C# anon method), and was wondering, can I return more than one value from a query?
For example, return the number of rows in a table as one output value, and also, as another output value, return the distinct number of rows?
Also, how does distinct work? Is this based on whether one field may be the same as another (thus classified as "distinct")?
I am using Sql Server 2005. Would there be a performance penalty if I return one value from one query, rather than two from one query?
Thanks
You could do your first question by doing this:
SELECT
COUNT(field1),
COUNT(DISTINCT field2)
FROM table
(For the first field you could do * if needed to count null values.)
Distinct means the definition of the word. It eliminates duplicate returned rows.
Returning 2 values instead of 1 would depend on what the values were, if they were indexed or not and other undetermined possible variables.
If you are meaning subqueries within the select statement, no you can only return 1 value. If you want more than 1 value you will have to use the subquery as a join.
If the inner query is inline in the SELECT, you may struggle to select multiple values. However, it is often possible to JOIN to a sub-query instead; that way, the sub-query can be named and you can get multiple results
SELECT a.Foo, a.Bar, x.[Count], x.[Avg]
FROM a
INNER JOIN (SELECT COUNT(1) AS [Count], AVG(something) AS [Avg]) x
ON x.Something = a.Something
Which might help.
DISTINCT does what it says. IIRC, you can SELECT COUNT(DISTINCT Foo) etc to query distinct data.
you can return multiple results in 3 ways (off the top of my head)
By having a select with multiple values eg: select col1, col2, col3
With multiple queries eg: select 1 ; select "2" ; select colA. you would get to them in a datareader by calling .NextRecord()
Using output parameters, declare the parameters before exec the query then get the value from them afterwards. eg: set #param1 = "2" . string myparam2 = sqlcommand.parameters["param1"].tostring()
Distinct, filters resulting rows to be unique.
Inner queries in the form:
SELECT * FROM tbl WHERE fld in (SELECT fld2 FROM tbl2 WHERE tbl.fld = tbl2.fld2)
cannot return multiple rows. When you need multiple rows from a secondary query, you usually need to do an inner join on the other query.
rows:
SELECT count(*), count(distinct *) from table
will return a dataset with one row containing two columns. Column 1 is the total number of rows in the table. Column 2 counts only distinct rows.
Distinct means the returned dataset will not have any duplicate rows. Distinct can only appear once usually directly after the select. Thus a query such as:
SELECT distinct a, b, c FROM table
might have this result:
a1 b1 c1
a1 b1 c2
a1 b2 c2
a1 b3 c2
Note that values are duplicated across the whole result set but each row is unique.
I'm not sure what your last question means. You should return from a query all the data relevant to the query. As for faster, only benchmarking can tell you which approach is faster.