Insert new column that adds a series from another column - sql

I have a table with dates and follower growth for each date and want to make a new column that depicts total followers gained.
How can I insert a new column that basically adds the 'new followers' column in to a summation series?
date | new followers
-----------------------
1/1/15 | 1
1/2/15 | 3
1/3/15 | 5
1/4/15 | 4
1/5/15 | 3
New table would look like
date | new followers | total followers gained
------------------------------------------------
1/1/15 | 1 | 1
1/2/15 | 3 | 4
1/3/15 | 5 | 9
1/4/15 | 4 | 13
1/5/15 | 3 | 16

This SQL will accomplish what you want with a Select. If it is really necessary to persist this value in a table, then you could use this SQL in a trigger. But since you could just calculate this amount on the fly, I'm not sure why you would persist it.
declare #tempTable table (theDt datetime, newFollowers int)
insert into #tempTable
select '1/1/15',1
UNION select '1/2/15',3
UNION select '1/3/15',5
UNION select '1/4/15',4
UNION select '1/5/15',3
select t1.theDt,
t1.newFollowers + SUM(case when t2.theDt IS not null then t2.newFollowers else 0 end) as "Total Followers"
from #tempTable t1
left outer join #tempTable t2 on t1.theDt > t2.theDt
group by t1.theDt, t1.newFollowers
order by t1.theDt

Related

SQL: How can I pick a cell value from one table as a condition to select another table

Hi I'm a new learner of SQL. How can I realize this process in SQL or perhaps with python if needed:
First, from table1, I randomly selected two results:
SELECT TOP 2 id, date
FROM table 1
WHERE date >= 2 AND date <= 6
ORDER BY RAND(CHECKSUM(*) * RAND())
+-----------+
| table1 |
+-----------+
| id | date |
+----+------+
| x | 3 |
| y | 4 |
+----+------+
I need to use the value x and y as conditions to display another table. For instance, using x, I can:
SELECT id, date
FROM table1
WHERE date >= 2 AND date <= 6 AND id = 'x'
ORDER BY date ASC
+-----------+
| table2 |
+-----------+
| id | date |
+----+------+
| x | 3 |
| x | 4 |
| x | 5 |
| x | 6 |
| x | 6 |
+----+------+
What I need is to get the length of table2 without duplication on date. For instance, table2 has 5 rows, but last two duplicate in date. So the final answer is 4 rows.
For id = y, I have to do the same thing (say table3) and compare the length of table3 and table2 to see if consistent.
If yes, then return the length (say, 4 rows); If no, then go back to table1 and select another two id (say, z and y).
I was thinking to use python to select value or create variables, then use python variables in SQL. But it is too much for a new learner. I really appreciate it if someone could help me out this process.
You can use subqueries with IN clause
Here is too a Version with two diemsnions, maybe this will help also
CREATE TABLE table1 ([id] varchar(2),[date] int)
GO
✓
SELECT id, date FROM table1
where date >= 2 and date <= 6
and id IN (
SELECT TOP 2 id FROM table1
WHERE date >= 2 and date <= 6
ORDER BY RAND(CHECKSUM(*) * RAND())
)
ORDER BY date ASC
GO
id | date
:- | ---:
SELECT id, date FROM table1
WHERE EXISTS (SELECT 1
FROM (
SELECT TOP 2 id,[date] FROM table1
WHERE date >= 2 and date <= 6
ORDER BY RAND(CHECKSUM(*) * RAND())) AS table2
WHERE table1.[id] = table2.[id]
AND table1.[date] = table2.[date])
GO
id | date
:- | ---:
db<>fiddle here

SQL (Omnisci) get common and uncommon values of a column

I'm using Omnisci to join two tables and I need the following:
Table 1:
poly_id | num_competitors
1 | 1
2 | 1
3 | 5
Table 2:
poly_id | num_stores
1 | 1
5 | 3
7 | 5
What I want:
poly_id | num_competitors | num_stores
1 | 1 | 1
2 | 1 | 0
3 | 5 | 0
5 | 0 | 3
7 | 0 | 5
I know in normal SQL you can do it with FULL JOIN or even with UNION, but Omnisci does not support any of these functions yet (it does support JOIN and LEFT JOIN though).
I've found a way to solve it. It's by creating a new empty table. Insert into it Table 1 and Table 2 and then make a group by on poly id in order to merge rows that have both num_competitors and num_stores.
CREATE TABLE competitors_stores ( poly_id integer, num_stores integer, num_competitors integer);
INSERT INTO competitors_stores ( SELECT poly_id, 0, num_competitors from competitors_geo)
INSERT INTO competitors_stores ( SELECT poly_id, num_stores, 0 from telepi_stores_geo)
CREATE TABLE num_competitors_stores AS (select poly_id, SUM(num_stores) AS num_stores, SUM(num_competitors) as num_competitors from competitors_stores group by poly_id);
DROP TABLE telepi_competitors_stores;
Anyway, I'm still open to hearing alternatives since I feel like this is not the best way to solve it.

Is there a way using SQL to insert duplicate rows into Table A depending upon the results of a number column in Table B?

I am using TSQL on SQL Server and have bumped into a challenge...
I am querying the data out of TableA and then inserting it into TableB. See my stored procedure code below for more info.
However as an added layer of complexity one of the Columns in TableA holds a numeric number (It can be any number from 0 to 50) and depending upon this number I have to make 'n' number of Duplicates for that specific row. (for example in TableA we have a column called TableA.RepeatNumber and this will dictate how many duplicate rows I need to create of this row in TableB. Its worth noting that some of the rows won't need any duplicates as they will have a value of 0 in TableA.RepeatNumber)
(This stored procedure below works fine to insert single rows into TableB.)
ALTER PROCEDURE [dbo].[Insert_rows]
#IDCode As NVarChar(20),
#UserName As NVarChar(20)
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Insert statements for procedure here
Insert INTO TableB (Status, Number, Date, Time, User)
SELECT Status, Number, date, Time, User,
FROM TableA where Status = 1 AND RepeatNumber > 0 AND Code = #IDCode AND User = #UserName
END
Any pointers on where I should look to find a solution to this problem (if it exists would be greatly appreciated.)
Best wishes
Dick
You can use a recursive CTE:
with a as (
select a.Status, a.Number, a.date, a.Time, a.User, a.RepeatNumber, 1 as seqnum
from tablea a
where Status = 1 and RepeatNumber > 0 and Code = #IDCode and User = #UserName
union all
select Status, Number, date, Time, User, RepeatNumber, seqnum + 1
from a
where seqnum < RepeatNumber
)
insert INTO TableB (Status, Number, Date, Time, User)
select Status, Number, date, Time, User
from a;
You only need up to 50 duplicates, so you don't have to worry about maximum recursion.
A numbers table can also be used for this purpose.
To achieve this using a numbers table and avoiding recursion which may have a performance penalty, you can do the following (if you already have an actual numbers table in your database you can just join to that and avoid the cte):
declare #TableA table(Status nvarchar(10),RepeatNumber int,[date] date,Time time,[User] nvarchar(10));
insert into #TableA values('Status 0',0,'20190101','00:00:00','User 0'),('Status 1',1,'20190101','01:01:01','User 1'),('Status 2',2,'20190102','02:02:02','User 2'),('Status 3',3,'20190103','03:03:03','User 3');
with t(t)as(select t from(values(1),(1),(1),(1),(1),(1),(1),(1))as t(t))
,n(n)as(select top 50 row_number()over(order by(select null)) from t,t t2)
select Status
,RepeatNumber
,[date]
,Time
,[User]
,n.n
from #TableA as a
join n
on a.RepeatNumber >= n.n
where RepeatNumber > 0
order by a.Status
,n.n;
Output
+----------+--------------+------------+------------------+--------+---+
| Status | RepeatNumber | date | Time | User | n |
+----------+--------------+------------+------------------+--------+---+
| Status 1 | 1 | 2019-01-01 | 01:01:01.0000000 | User 1 | 1 |
| Status 2 | 2 | 2019-01-02 | 02:02:02.0000000 | User 2 | 1 |
| Status 2 | 2 | 2019-01-02 | 02:02:02.0000000 | User 2 | 2 |
| Status 3 | 3 | 2019-01-03 | 03:03:03.0000000 | User 3 | 1 |
| Status 3 | 3 | 2019-01-03 | 03:03:03.0000000 | User 3 | 2 |
| Status 3 | 3 | 2019-01-03 | 03:03:03.0000000 | User 3 | 3 |
+----------+--------------+------------+------------------+--------+---+

sql group by personalised condition

Hi,I have a column as below
+--------+--------+
| day | amount|
+--------+---------
| 2 | 2 |
| 1 | 3 |
| 1 | 4 |
| 2 | 2 |
| 3 | 3 |
| 4 | 3 |
+--------+--------+
now I want something like this sum day 1- day2 as row one , sum day1-3 as row 2, and so on.
+--------+--------+
| day | amount|
+--------+---------
| 1-2 | 11 |
| 1-3 | 14 |
| 1-4 | 17 |
+--------+--------+
Could you offer any one help ,thanks!
with data as(
select 2 day, 2 amount from dual union all
select 1 day, 3 amount from dual union all
select 1 day, 4 amount from dual union all
select 2 day, 2 amount from dual union all
select 3 day, 3 amount from dual union all
select 4 day, 3 amount from dual)
select distinct day, sum(amount) over (order by day range unbounded preceding) cume_amount
from data
order by 1;
DAY CUME_AMOUNT
---------- -----------
1 7
2 11
3 14
4 17
if you are using oracle you can do something like the above
Assuming the day range in left column always starts from "1-", What you need is a query doing cumulative sum on the grouped table(dayWiseSum below). Since it needs to be accessed twice I'd put it into a temporary table.
CREATE TEMPORARY TABLE dayWiseSum AS
(SELECT day,SUM(amount) AS amount FROM table1 GROUP BY day ORDER BY day);
SELECT CONCAT("1-",t1.day) as day, SUM(t2.amount) AS amount
FROM dayWiseSum t1 INNER JOIN dayWiseSum
t2 ON t1.day > t2.day
--change to >= if you want to include "1-1"
GROUP BY t1.day, t1.amount ORDER BY t1.day
DROP TABLE dayWiseSum;
Here's a fiddle to test with:
http://sqlfiddle.com/#!9/c1656/1/0
Note: Since sqlfiddle isn't allowing CREATE statements, I've replaced dayWiseSum with it's query there. Also, I've used "Text to DDL" option to paste the exact text of the table from your question to generate the create table query :)

SELECT set of most recent id, amount FROM table, where id occurs many times

I have a table recording the amount of data transferred by a given service on a given date. One record is entered daily for a given service.
I'd like to be able to retrieve the most recent amount for a set of services.
Example data set:
serviceId | amount | date
-------------------------------
1 | 8 | 2010-04-12
2 | 11 | 2010-04-12
2 | 14 | 2010-04-11
3 | 9 | 2010-04-11
1 | 6 | 2010-04-10
2 | 5 | 2010-04-10
3 | 22 | 2010-04-10
4 | 17 | 2010-04-19
Desired response (service ids 1,2,3):
serviceId | amount | date
-------------------------------
1 | 8 | 2010-04-12
2 | 11 | 2010-04-12
3 | 9 | 2010-04-11
Desired response (service ids 2, 4):
serviceId | amount | date
-------------------------------
2 | 11 | 2010-04-12
4 | 17 | 2010-04-19
This retrieves the equivalent as running the following once per serviceId:
SELECT serviceId, amount, date
FROM table
WHERE serviceId = <given serviceId>
ORDER BY date DESC
LIMIT 0,1
I understand how I can retrieve the data I want in X queries. I'm interested to see how I can retrieve the same data using either a single query or at the very least less than X queries.
I'm very interested to see what might be the most efficient approach. The table currently contains 28809 records.
I appreciate that there are other questions that cover selecting the most recent set of records. I have examined three such questions but have been unable to apply the solutions to my problem.
select m.*
from (
select serviceId, max(date) as MaxDate
from MyTable
group by serviceId
) mm
inner join MyTable m on mm.serviceId = m.serviceId and mm.MaxDate = m.date
If you wish to filter by serviceId, you can do:
select m.*
from (
select serviceId, max(date) as MaxDate
from MyTable
where serviceId in (1, 2, 3)
group by serviceId
) mm
inner join MyTable m on mm.serviceId = m.serviceId and mm.MaxDate = m.date
SELECT serviceId, amount, date
FROM table as t
WHERE NOT EXIST (
SELECT * FROM table as x
WHERE t.serviceId = x.serviceID AND t.date < x.date
)
if you want to filter out some serviceIds than
SELECT serviceId, amount, date
FROM table as t
WHERE NOT EXIST (
SELECT * FROM table as x
WHERE t.serviceId = x.serviceID AND t.date < x.date
)
AND serviceId in (2, 4)