What is an alternative way to sum a column without aggregate function? - sql

I using a software where is partly SQL server based. The software is made by another company so I do not have full access to the sql editing part. In simple terms, I have a datebase and it is stored using sql formats. I can fiddle with some areas but there are limitation to how much I can customize and the type of syntax that can be used.
Aggregate function such as SUM() cannot be used and I am trying to find an alternative method to reach a similar/same result. I know that the normal way to sum is as below but SUM() and GROUP BY cannot be used.
I am still inexperienced in sql, I kindly ask for your advices.
Thank you very much in advance.
DBMS: Microsoft SQL server
SELECT *,SUM(value)
FROM table
GROUP BY ID1
Note:
ID1 continues to expand
ID2 consist a fix set of value (AA, BB, CC, DD, EE) ONLY
I don't need to group it but I don't know how to do it without grouping at the moment
TABLE
ID1
ID2
Value
001
AA
10
001
BB
21
001
CC
2
001
DD
16
002
AA
7
002
CC
8
003
AA
10
003
BB
9
003
AA
11
RESULT
ID1
ID2
Value
SUM
001
AA
10
49
001
BB
21
49
001
CC
2
49
001
DD
16
49
002
AA
7
15
002
CC
8
15
003
AA
10
30
003
BB
9
30
003
AA
11
30

Here is an option using the window function sum() over(). Notice there is no need for a GROUP BY or subquery.
The window functions are invaluable and well worth your time getting comfortable with them.
Example
Select *
,Sum = sum(Value) over (partition by ID1)
From YourTable
Results
ID1 ID2 Value Sum
001 AA 10 49
001 BB 21 49
001 CC 2 49
001 DD 16 49
002 AA 7 15
002 CC 8 15
003 AA 10 30
003 BB 9 30
003 AA 11 30

Related

Can someone help me to write the Oracle SQL query for the following data [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 12 months ago.
Improve this question
table1:
NAME
SAL
ab
34
ab
322
ab_d
34
ab_d
322
aa
34
aa
322
bb
34
bb
322
ac
65
ac_d
876
table 2:
col1
col2
col3
col4
ab
ab_d
aa
bb
ac
ac_d
ss
pp
this table2 also contains multiple rows
case 1: If I use table1.name = ab as a where condition,
the output should be,
ab, ab_d, aa, bb records
select * from table1 t1
where t1.name = 'ab';
NAME
SAL
ab
34
ab
322
ab_d
34
ab_d
322
aa
34
aa
322
bb
34
bb
322
(or)
case 2: If I use table2.col2 = ac_d as a where condition,
the output should be,
ac, ac_d, ss, pp records
select * from table1 t1
where t1.name = 'ac_d';
NAME
SAL
ac
34
ac
322
ac_d
34
ac_d
322
ss
34
ss
322
pp
34
pp
322
I am unable to write query....
You can do:
select y.*
from table2 x
join table1 y on y.name in (x.col1, x.col2, x.col3, x.col4)
where 'ab' in (x.col1, x.col2, x.col3, x.col4);
Result:
NAME SAL
----- ---
ab 34
ab 322
ab_d 34
ab_d 322
aa 34
aa 322
bb 34
bb 322
See running example at db<>fiddle.
The 3rd table is identical to the first table. Please provide CREATE TABLE scripts with data types, Primary keys and Foreign key constraints.
Looking at the structure of the 2nd table and the values in col2 in the first table I think you are going to need an UNPIVOT command
This will take the 2nd table and use the first column as an entity reference, take the column names from the other columns as use them as attributes and take the column value and use it as the value.
E.g. If you had a table:
Colour Jan Feb Mar
RED 20 15 12
BLUE 8 7 15
The UNPIVOT command would produce
Colour Month Amt
RED Jan 20
RED Feb 15
RED Mar 12
BLUE Jan 8
BLUE Feb 7
BLUE Mar 15

Want to retreive data in required format from SQL SERVER table

I have a view as follows:
id paperid papercode papername marks1 marks2 total
1 1 001 paper-1 10 35 45
2 2 001 paper-2 12 40 52
3 3 002 paper-3 9 30 39
Now, I want data as below:
id paperid papercode papername marks1 marks2 total
1 1 001 001 22 75 97
3 3 002 paper-3 9 30 39
You can try below -
select min(id),min(paperid),papercode,min(papername),sum(marks1),sum(marks2),sum(marks3)
from tablename
group by papercode

SAS/SQL: Combine two columns while retaining others

I need to merge two data sets. Each data set contains a sequential observation number. The first data set contains only the first observation. The second data set contains all subsequent observations. Not all subjects have the same number of observations.
The problem is as follows. There are two different types of subject. The type is contained only in the first data set. When I merge the two data sets together, the type is missing on all observations but the first for each subject. Please see my example below.
I would like to know how to do this with both SQL and a DATA step. My real data sets are not large, so efficiency of processing is not major a concern.
I have tried using RETAIN, but as the second data set doesn't contain the TYPE variable, there is no value to retain. Regarding SQL, it seems like UNION should work, and there are countless examples of UNION on the internet, but they all involve a single variable. I need to know how to union the Observation variable by ID while retaining the Amount and assigning the Type.
Example
data set1;
input ID $
Observation
Type $
Amount
;
datalines;
002 1 A 15
026 1 A 30
031 1 B 7
028 1 B 10
036 1 A 22
;
run;
data set2;
input ID $
Observation
Amount
;
datalines;
002 2 11
002 3 35
002 4 13
002 5 12
026 2 21
026 3 12
026 4 40
031 2 11
028 2 27
036 2 10
036 3 15
036 4 16
036 5 12
036 6 20
;
run;
proc sort data = set1;
by ID
Observation
;
run;
proc sort data = set2;
by ID
Observation
;
run;
data merged;
merge set1
set2
;
by ID
Observation
;
run;
This gives
ID Observation Type Amount
002 1 A 15
002 2 11
002 3 35
002 4 13
002 5 12
026 1 A 30
026 2 21
026 3 12
026 4 40
028 1 B 10
028 2 27
031 1 B 7
031 2 11
036 1 A 22
036 2 10
036 3 15
036 4 16
036 5 12
036 6 20
However, what I need is
ID Observation Type Amount
002 1 A 15
002 2 A 11
002 3 A 35
002 4 A 13
002 5 A 12
026 1 A 30
026 2 A 21
026 3 A 12
026 4 A 40
028 1 B 10
028 2 B 27
031 1 B 7
031 2 B 11
036 1 A 22
036 2 A 10
036 3 A 15
036 4 A 16
036 5 A 12
036 6 A 20
I'm sure there are other ways to do it, but this is how I'd do it.
First, stack the data keeping only the common fields.
data new;
set set1 (drop = TYPE) set2;
run;
Then merge the type field back over.
proc sql;
create table new2 as select
a.*,
b.TYPE
from new a
left join set1 b
on a.id=b.id;
quit;
Proc SQL:
proc sql;
create table want as
select coalesce(a.id,b.id) as id,observation,type,amount from (select * from set1(drop=type) union
select * from set2) a left join set1 (keep=id type) b
on a.id=b.id;
quit;
The DATA step method is straight forward, just use SET with BY to interleave the records. You need to create a NEW variable to retain the values. If you want you can drop the old one and rename the new one to have its name.
data want ;
set set1 set2 ;
by id ;
if first.id then new_type=type;
retain new_type;
run;
For SQL use the method that #JJFord3 posted to first union the common fields and then merge on the TYPE flag. You can combine into a single statement.
proc sql;
create table want as
select a.*,b.type
from
(select id,observation,amount from set1
union
select id,observation,amount from set2
) a
left join set1 b
on a.id = b.id
order by 1,2
;
quit;

DB2:how to get top

I have a table having data like
pin id name
3 33 jjj
2 22 bbb
1 111 aaaa
1 112 aa
1 113 aaa
4 44 kkk
I want to print rows of the table where if count(*) group by pin =1 (i.e single entry in table ) print the row
if count(*) group by pin >2 then print first two rows
so my out put should be
pin id name
3 33 jjj
2 22 bbb
1 111 aaaa
1 112 aa
4 44 kkk
Use row_number() OVER(partion by pin order by id) as rownum function . Where rownum <3
. As #Clockwork-Muse said, you need to define an order becase you need to say what do you want to see if there are more than 2 rows for a particular pin.
This will generate you desired output.

Creating a field(s) that counts days within a month from date range?

Similar to the following:
Count days within a month from date range
I want to find a way, within the MS-Access Query Design environment, to create fields that count the number of month/year days within a date range.
Here is what I want the data to look like:
Row | StartDate | EndDate | #DaysJan2010 | #DaysFeb2010 | #DaysMarch2010
001 01/02/2010 02/04/2012 29 28 31
002 01/02/2010 01/05/2010 4 0 0
003 04/02/2010 05/05/2010 0 0 0
004 01/02/2010 02/04/2012 29 28 31
005 02/02/2012 02/03/2012 0 2 0
Please keep in mind that both month and year are important because I need to be able to distinguish between the number of days that fall within a given date range for January 2010 and January 2011, as opposed to just the number of days within a given date range that are in January.
If there is a systematic way of performing of creating these fields by using SQL in Access, that would be my preferred method.
However, in the event that it is impossible (or very difficult) to do so, I would like to know how to build each field in the expression builder, so that I may at least be able to generate the count fields one at a time.
As always, thank you very much for your time.
There are cases where date manipulations can be aided by a "dates table". Similar to a "numbers table", a "dates table" is a table containing one row for every date in a given range, usually covering the entire range of dates that one could expect to encounter in the actual data.
For sample data in a table named [SampleData]
Row StartDate EndDate
--- ---------- ----------
001 2010-01-02 2012-02-04
002 2010-01-02 2010-01-05
003 2010-04-02 2010-05-05
004 2010-01-02 2012-02-04
005 2012-02-02 2012-02-03
and a [DatesTable] that is simply
theDate
----------
2010-01-01
2010-01-02
2010-01-03
...
2012-12-30
2012-12-31
the query
SELECT
sd.Row,
dt.theDate,
Year(dt.theDate) AS theYear,
Month(dt.theDate) AS theMonth
FROM
SampleData AS sd
INNER JOIN
DatesTable AS dt
ON dt.theDate >= sd.StartDate
AND dt.theDate <= sd.EndDate
returns a row for each date in the interval for each [SampleData].[Row] value. (For this particular sample data, that's 1568 rows in total.)
Performing an aggregation on that
SELECT
Row,
theYear,
theMonth,
COUNT(*) AS NumberOfDays
FROM
(
SELECT
sd.Row,
dt.theDate,
Year(dt.theDate) AS theYear,
Month(dt.theDate) AS theMonth
FROM
SampleData AS sd
INNER JOIN
DatesTable AS dt
ON dt.theDate >= sd.StartDate
AND dt.theDate <= sd.EndDate
) AS allDates
GROUP BY
Row,
theYear,
theMonth
gives us all of the counts
Row theYear theMonth NumberOfDays
--- ------- -------- ------------
001 2010 1 30
001 2010 2 28
001 2010 3 31
001 2010 4 30
001 2010 5 31
001 2010 6 30
001 2010 7 31
001 2010 8 31
001 2010 9 30
001 2010 10 31
001 2010 11 30
001 2010 12 31
001 2011 1 31
001 2011 2 28
001 2011 3 31
001 2011 4 30
001 2011 5 31
001 2011 6 30
001 2011 7 31
001 2011 8 31
001 2011 9 30
001 2011 10 31
001 2011 11 30
001 2011 12 31
001 2012 1 31
001 2012 2 4
002 2010 1 4
003 2010 4 29
003 2010 5 5
004 2010 1 30
004 2010 2 28
004 2010 3 31
004 2010 4 30
004 2010 5 31
004 2010 6 30
004 2010 7 31
004 2010 8 31
004 2010 9 30
004 2010 10 31
004 2010 11 30
004 2010 12 31
004 2011 1 31
004 2011 2 28
004 2011 3 31
004 2011 4 30
004 2011 5 31
004 2011 6 30
004 2011 7 31
004 2011 8 31
004 2011 9 30
004 2011 10 31
004 2011 11 30
004 2011 12 31
004 2012 1 31
004 2012 2 4
005 2012 2 2
We can then report on that, or crosstab it, or do any number of other fun things.
Side note:
One circumstance where a "dates table" can be very useful is when we have to deal with Statutory Holidays. That is because
Sometimes the "day off" for a Statutory Holiday is not the actual day. If "International Bacon Day" falls on a Sunday then we might get the Monday off.
Some Statutory Holidays can be tricky to calculate. For example, Good Friday for us Canadians is (if I remember correctly) "the Friday before the first Sunday after the first full moon after the Spring Equinox".
If we have a "dates table" then we can add a [StatutoryHoliday] Yes/No field to flag all of the (observed) holidays and then use ... WHERE NOT StatutoryHoliday to exclude them.