Many Thanks for having to take your time to give some suggestions/help.
I have below data and I would like to calculate the total/sum across all the column group by year using SQL Server 2012. Below data is the score for four countries for different games, I would like to get the total score for all the countries together (4 distinct) group by year.
SELECT
,Country
,SUM(Football) AS Football
,SUM(Basket) AS Basket
,SUM(Ball) AS Ball
,SUM(Volleyball) Volleyball
,Year
From CountryScore
GROUP BY
GROUP BY SETS(Year,())
Sample Data
Expected Result
You can try to use SUM with add to your expect addition number columns.
CREATE TABLE CountryScore(
year int,
Football int,
Basket int,
Volleyball int
);
INSERT INTO CountryScore VALUES (1996,4,6,7);
INSERT INTO CountryScore VALUES (1996,4,6,7);
INSERT INTO CountryScore VALUES (1996,6,7,7);
INSERT INTO CountryScore VALUES (1996,6,7,7);
INSERT INTO CountryScore VALUES (2000,7,4,8);
INSERT INTO CountryScore VALUES (2000,7,6,5);
INSERT INTO CountryScore VALUES (2000,6,6,6);
INSERT INTO CountryScore VALUES (2000,6,8,8);
Query 1:
SELECT
[Year]
,SUM(Football + Basket + Volleyball) AS 'Total Score'
From CountryScore
GROUP BY
[Year]
Results:
| Year | Total Score |
|------|-------------|
| 1996 | 74 |
| 2000 | 77 |
If your value column possible be NULL, you can add ISNULL function to prevent it and set NULL to 0.
SELECT
[Year]
,SUM(ISNULL(Football,0) + ISNULL(Basket,0) + ISNULL(Volleyball,0)) AS 'Total Score'
From CountryScore
GROUP BY
[Year]
If you want play wise then you can use the below query
SELECT year,sum(Football)Football,sum(Basket)Basket,sum(Volleyball) Volleyball
From #CountryScore
group by grouping sets(year,())
Thanks
Sasi
Related
I have an ID column, and a time column. I want to group the IDs by average time.
IDs: 1234, 1234, 5678, 5678
Times: 13:21, 19:55, 14:25, 15:04
select ID,
avg(cast(CONCAT(left(cast(Time as varchar),2),substring(cast(Time as varchar),4,2)) as int)*1.0)
It does return a result, but I don't believe the average to be correct as the average time can be outside of normal time constraints (aka the minutes can be > 59).
time stores a point in time, not a duration. What would you do for a duration longer than a day? You should instead store either the duration in seconds, minutes, what have you, and format it as hh:mm etc. when you want to display it. Or better yet, store a start date and end date, which is more complete information, and you can always derive the duration (in whatever format you like) from that.
Anyway, dealing with what you have, and assuming this table and sample data:
CREATE TABLE dbo.BadChoices
(
ID int,
DurationWithWrongType time(0)
);
INSERT dbo.BadChoices(ID, DurationWithWrongType) VALUES
(1234, '13:21'),
(1234, '19:55'),
(5678, '14:25'),
(5678, '15:04');
You could I suppose do:
SELECT ID, AvgDuration = CONVERT(DECIMAL(10,2),
AVG(DATEDIFF(MINUTE, '00:00', DurationWithWrongType)*1.0))
FROM dbo.BadChoices
GROUP BY ID;
Output:
ID
AvgDuration
1234
998.00
5678
884.50
Example db<>fiddle
If you want the display to be HH:MM, and you know for sure your durations will always be < 24 hours, you could do:
;WITH src AS
(
SELECT ID, AvgDuration = CONVERT(DECIMAL(10,2),
AVG(DATEDIFF(MINUTE, '00:00', DurationWithWrongType)*1.0))
FROM dbo.BadChoices
GROUP BY ID
)
SELECT ID, AvgDuration,
AvgDurHHMMSS = CONVERT(time(0), DATEADD(SECOND, AvgDuration*60, '00:00'))
FROM src;
Output:
ID
AvgDuration
AvgDurHHMMSS
1234
998.00
16:38:00
5678
884.50
14:44:30
Example db<>fiddle
We have to cast to datetime to be able to cast to float. We can then find the average and cast back to datetime and then back to time.
A second alternative is to convert the time into minutes, get the average and then use dateadd() and cast back to time
create table times(
t time);
insert into times values
('13:21'),
('19:55'),
('14:25'),
('15:04');
GO
4 rows affected
select
cast(
cast(
avg(
cast(
cast(t
as datetime)
as float)
)
as datetime)
as time)
from times
GO
| (No column name) |
| :--------------- |
| 15:41:15 |
select
cast(
dateadd(second,
avg(
DateDiff(second,0,t)
),
2000-01-01)
as time)
from times
GO
| (No column name) |
| :--------------- |
| 15:41:15 |
db<>fiddle here
I have a stored procedure that has a table for a parameter with two columns: From and To. Both int. It is used for searching scores.
The example of the table is
+-----------+-------+----+
| RowNumber | From | To |
+-----------+-------+----+
| 1 | 0 | 30 |
| 2 | 60 | 80 |
+-----------+-------+----+
How can I search a table to have results that include all scores between 0 and 30 and 60 and 80?
I had tried between inside a while loop but nothing.
This is a guess in the absence of a reply, however, maybe...
CREATE TABLE Score (ID int IDENTITY(1,1),
Score int);
INSERT INTO Score
VALUES (65),(17),(97),(14),(34),(79),(37),(87),(65),(63),(15),(75),(05),(25),(38),(28),(88);
GO
CREATE TABLE ScoreRange (ID int IDENTITY(1,1),
[From] int, --Try to avoid keywords, and especially reserved words, for column names
[To] int); --Try to avoid keywords, and especially reserved words, for column names
INSERT INTO ScoreRange
VALUES (0,30),
(60,80);
GO
SELECT *
FROM Score S;
SELECT S.*
FROM Score S
JOIN ScoreRange SR ON S.Score BETWEEN SR.[From] AND SR.[To];
GO
DROP TABLE Score;
DROP TABLE ScoreRange;
It's kinda hard to answer without sample data - but I think you are looking for something like this:
SELECT t.*
FROM YourTable As t
JOIN #TVP As p ON t.Score >= p.[From] AND t.Score <= p.[To]
select * from t
where exists (
select 1 from ranges r
where t.val between r.from and r.to
);
Database Records:
I want to represent as record set using stored procedure.
I have many records likewise in MS SQL DataBase.
It will be Listing record groupby A, B, C .. Z wize..
Automatically insert the Alphabets while got output from SQL Table.
I want below output from procedure..
How it will possible using Stored Procedure..?
You can use LEFT and UNION for this, though you will still get a 3 columns row for the rows that contains only the first letter:
Create and populate sample table (Please save us this step in your future questions)
DECLARE #T as TABLE
(
Name varchar(20),
Location varchar(20),
CreatedOn date
)
INSERT INTO #T VALUES
('Alex macwan', 'New york', '2015-12-10'),
('Jone Dinee', 'Denmark', '2016-05-01'),
('Jolly llb', 'USA', '2016-01-02'),
('Amin Mark', 'India', '2015-01-08'),
('Ben Denis', 'Brazil', '2015-10-02')
The query:
SELECT Name, Location, CreatedOn
FROM #T
UNION
SELECT LEFT(Name, 1), NULL, NULL
FROM #T
ORDER BY Name
Results:
Name Location CreatedOn
-------------------- -------------------- ----------
A NULL NULL
Alex macwan New york 2015-12-10
Amin Mark India 2015-01-08
B NULL NULL
Ben Denis Brazil 2015-10-02
J NULL NULL
Jolly llb USA 2016-01-02
Jone Dinee Denmark 2016-05-01
I have a table WHERE there's a column that has QTY Ranges like 1-5, 6-9 etc and prices in another column. i.e
Price QTY
------------------------
Price Qty Range
----- ----------
45 1-5
35 6-9
30 10-18
Now I want to get the result from the table where Qty is 7 Therefore Price returned should be 35 ( since Qty 7 falls in range 6-9
Any help greatly appriciated
Try this :-
Declare #val int
Set #val=7
;with cte(price,startVal,endVal) as
( Select price,
parsename(replace([Qty Range],'-','.'),2),
parsename(replace([Qty Range],'-','.'),1)
from yourTable
)
Select Price from cte
where #val between startVal and endVal
Result : 35
Demo in SQL FIDDLE
If you can't redesign the table to be sane, you can use a couple of CTEs to reconstruct it as a sane table for this query:
declare #PriceRanges table (Price int,QtyRange varchar(20))
insert into #PriceRanges (Price,QtyRange) values
(45,'1-5'),
(35,'6-9'),
(30,'10-18')
declare #Search int
set #Search = 7
;with FoundDashes as (
select Price,QtyRange,CHARINDEX('-',QtyRange) as DashPos
from #PriceRanges
)
, SaneRanges as (
select Price,CONVERT(int,SUBSTRING(QtyRange,1,DashPos-1)) as LowRange,CONVERT(int,SUBSTRING(QtyRange,DashPos+1,8000)) as HighRange
from FoundDashes
)
select Price from SaneRanges where #Search between LowRange and HighRange
Produces 35 as a result.
I'm having a hard time getting my head around a query im trying to build with SQL Server 2005.
I have a table, lets call its sales:
SaleId (int) (pk) EmployeeId (int) SaleDate(datetime)
I want to produce a report listing the total number of sales by an employee for each day in a given data range.
So, for example I want the see all sales in December 1st 2009 - December 31st 2009 with an output like:
EmployeeId Dec1 Dec2 Dec3 Dec4
1 10 10 1 20
2 25 10 2 2
..etc however the dates need to be flexible.
I've messed around with using pivot but cant quite seem to get it, any ideas welcome!
Here's a complete example. You can change the date range to fit your needs.
use sandbox;
create table sales (SaleId int primary key, EmployeeId int, SaleAmt float, SaleDate date);
insert into sales values (1,1,10,'2009-12-1');
insert into sales values (2,1,10,'2009-12-2');
insert into sales values (3,1,1,'2009-12-3');
insert into sales values (4,1,20,'2009-12-4');
insert into sales values (5,2,25,'2009-12-1');
insert into sales values (6,2,10,'2009-12-2');
insert into sales values (7,2,2,'2009-12-3');
insert into sales values (8,2,2,'2009-12-4');
SELECT * FROM
(SELECT EmployeeID, DATEPART(d, SaleDate) SaleDay, SaleAmt
FROM sales
WHERE SaleDate between '20091201' and '20091204'
) src
PIVOT (SUM(SaleAmt) FOR SaleDay
IN ([1],[2],[3],[4],[5],[6],[7],[8],[9],[10],[11],[12],[13],[14],[15],[16],[17],[18],[19],[20],[21],[22],[23],[24],[25],[26],[27],[28],[29],[30],[31])) AS pvt;
Results (actually 31 columns (for all possible month days) will be listed, but I'm just showing first 4):
EmployeeID 1 2 3 4
1 10 10 1 20
2 25 10 2 2
I tinkered a bit, and I think this is how you can do it with PIVOT:
select employeeid
, [2009/12/01] as Dec1
, [2009/12/02] as Dec2
, [2009/12/03] as Dec3
, [2009/12/04] as Dec4
from sales pivot (
count(saleid)
for saledate
in ([2009/12/01],[2009/12/02],[2009/12/03],[2009/12/04])
) as pvt
(this is my table:
CREATE TABLE [dbo].[sales](
[saleid] [int] NULL,
[employeeid] [int] NULL,
[saledate] [date] NULL
data is: 10 rows for '2009/12/01' for emp1, 25 rows for '2009/12/01' for emp2, 10 rows for '2009/12/02' for emp1, etc.)
Now, i must say, this is the first time I used PIVOT and perhaps I am not grasping it, but this seems pretty useless to me. I mean, what good is it to have a crosstab if you cannot do anything to specify the columns dynamically?
EDIT: ok- dcp's answer does it. The trick is, you don't have to explicitly name the columns in the SELECT list, * will actually correctly expand to a column for the first 'unpivoted' column, and a dynamically generated column for each value that appears in the FOR..IN clause in the PIVOT construct.