Duplicate all rows n times but change one column value each time - sql

Given a table in SQL such as the following:
Porfolio_num
Sim_num
SECID
FV
0
0
TB20230421
34,000
0
0
TB20230521
38,000
0
0
TB20230421
34,000
I'd like to duplicate it 5 times, each time incrementing the values in columns Portfolio_num and Sim_num by one.
The desired outcome is:
Portfolio_num
Sim_num
SECID
FV
0
0
TB20230421
34,000
0
0
TB20230521
38,000
0
0
TB20230621
40,000
1
1
TB20230421
34,000
1
1
TB20230521
38,000
1
1
TB20230621
40,000
2
2
TB20230421
34,000
2
2
TB20230521
38,000
2
2
TB20230621
40,000
3
3
TB20230421
34,000
3
3
TB20230521
38,000
3
3
TB20230621
40,000
4
4
TB20230421
34,000
4
4
TB20230521
38,000
4
4
TB20230621
40,000
5
5
TB20230421
34,000
5
5
TB20230521
38,000
5
5
TB20230621
40,000
Query to create the table:
CREATE TABLE test (
Portfolio_num int,
Sim_num int,
SECID varchar(10),
FV int
)
INSERT INTO test (Portfolio_num, Sim_num, SECID, FV)
VALUES
(0,0, 'TB20230421', 34000),
(0,0, 'TB20230521', 38000),
(0,0, 'TB20230621', 40000)

Try this:
DROP TABLE IF EXISTS #PortfolioData;
CREATE TABLE #PortfolioData (
Porfolio_num INT,
Sim_num INT,
SECID VARCHAR(10),
FV MONEY
);
INSERT INTO #PortfolioData (Porfolio_num, Sim_num, SECID, FV)
VALUES
(0, 0, 'TB20230421', 34000),
(0, 0, 'TB20230521', 38000),
(0, 0, 'TB20230421', 40000);
SELECT DS.[n] AS [Porfolio_num]
,DS.[N] AS [Sim_num]
,PD.[SECID]
,PD.[FV]
FROM #PortfolioData PD
CROSS APPLY
(
SELECT TOP (6) ROW_NUMBER() OVER(ORDER BY number) -1
FROM master..spt_values
) DS (n)
ORDER BY DS.[n]
In the cross apply we are just generating a data source with X rows (you can adjust it to your real needs).

How about a cross join:
SELECT
t2.num AS Portfolio_num,
t2.num AS Sim_num,
t1.SECID,
t1.FV
FROM test t1
CROSS JOIN (
SELECT 0 AS num UNION ALL
SELECT 1 UNION ALL
...
SELECT 5
) t2
ORDER BY 1, 2;
You may replace the subquery aliased as t2 with a bona fide sequence table.

Related

Get max record for each group of records, link multiple tables

I seek to find the maximum timestamp (ob.create_ts) for each group of marketid's (ob.marketid), joining tables obe (ob.orderbookid = obe.orderbookid) and market (ob.marketid = m.marketid). Although there are a number of solutions posted like this for a single table, when I join multiple tables, I get redundant results. Sample table and desired results below:
table: ob
orderbookid
marketid
create_ts
1
1
1664635255298
2
1
1664635255299
3
1
1664635255300
4
2
1664635255301
5
2
1664635255302
6
2
1664635255303
table: obe
orderbookentryid
orderbookid
entryname
1
1
'entry-1'
2
1
'entry-2'
3
1
'entry-3'
4
2
'entry-4'
5
2
'entry-5'
6
3
'entry-6'
7
3
'entry-7'
8
4
'entry-8'
9
5
'entry-9'
10
6
'entry-10'
table: m
marketid
marketname
1
'market-1'
2
'market-2'
desired results
ob.orderbookid
ob.marketid
obe.orderbookentryid
obe.entryname
m.marketname
3
1
6
'entry-6'
'market-1'
3
1
7
'entry-7'
'market-1'
6
2
10
'entry-10'
'market-2'
Use ROW_NUMBER() to get a properly filtered ob table. Then JOIN the other tables onto that!
WITH
ob_filtered AS (
SELECT
orderbookid,
marketid
FROM
(
SELECT
*,
ROW_NUMBER() OVER (
PARTITION BY
marketid
ORDER BY
create_ts DESC
) AS create_ts_rownumber
FROM
ob
) ob_with_rownumber
WHERE
create_ts_rownumber = 1
)
SELECT
ob_filtered.orderbookid,
ob_filtered.marketid,
obe.orderbookentryid,
obe.entryname,
m.marketname
FROM
ob_filtered
JOIN m
ON m.marketid = ob_filtered.marketid
JOIN obe
ON ob_filtered.orderbookid = obe.orderbookid
;

LEFT JOIN with tables having boolean data producing unexpected result set

A Table_1 with only column BOOLVALUE(int) having records as
1
1
0
0
0
and another Table_2 with only column BOOLVALUE(int) having records as
1
1
1
0
0
.. I am trying to run a query
select t1.BOOLVALUE from Table_1 t1
left join Table_2 t2 on t1.BOOLVALUE=t2.BOOLVALUE
and to my surprise output is not what I expected.There are 12 rows with 6 1's and 6 0's. But doesn't this invalidates how joins work ?
12 rows is completely expected as you have 2 rows related to 3 rows, resulting in 6 rows, and 3 rows related to 2 rows resulting in 6 rows; add these together and you get 12.
When you JOIN all related rows are JOINed based on the ON clause. Your ON clause is t1.BOOLVALUE=t2.BOOLVALUE. This means all the 1s inTable_1 relate to all the 1s in Table_2; so that's 2 rows related to 3 rows (2 * 3). Then all the 0s inTable_1 relate to all the 0s in Table_2; so that's 3 rows related to 2 rows (3 * 2). Hence (2 * 3) + (3 * 2) = 6 + 6 = 12.
If we add an ID column to the table, this might become a little clearer.
Let's say you have 2 tables like this:
ID1
I1
1
1
2
1
3
0
4
0
5
0
ID2
I2
1
1
2
1
3
1
4
0
5
0
Then lets say you have the following query:
SELECT T1.ID1,
T2.ID2,
T1.I1,
T2.I2
FROM dbo.Table1 T1
JOIN dbo.Table2 T2 ON T1.I1 = T2.I2
ORDER BY T1.ID1
T2.ID2;
This would result in the following data set:
ID1
ID2
I1
I2
1
1
1
1
1
2
1
1
1
3
1
1
2
1
1
1
2
2
1
1
2
3
1
1
3
4
0
0
3
5
0
0
4
4
0
0
4
5
0
0
5
4
0
0
5
5
0
0
Here you can see you have a many to many join, and where the "extra" rows are coming from.
If you LEFT JOINed on the ID and I columns, starting at Table1, you would get 5 rows, with 1 row having NULL values for ID2 and I2 (in this case because although the ID matched, I did not):
SELECT T1.ID1,
T2.ID2,
T1.I1,
T2.I2
FROM dbo.Table1 T1
LEFT JOIN dbo.Table2 T2 ON T1.ID1 = T2.ID1
AND T1.I1 = T2.I2
ORDER BY T1.ID1
T2.ID2;
ID1
ID2
I1
I2
1
1
1
1
2
2
1
1
3
NULL
0
NULL
4
4
0
0
5
5
0
0
When you join on a column of which has repeating values the number of rows returned is the product of the number of matching values in the 2 tables.
In this case there are 2 1's in table 1 and 3 in table 2 so SQL returns the 6 possible combinations (2 x 3). As there are 3 x 2 zero combinations you get 12 rows in total.
If you did a cross join you would get 25 rows back (5 x 5).

How to Calculate. It's Hard to calculate count(*) of table with existing Sql query

I have a form which have stars for rating from 1-5
i have count each user hits over individual value
Now i need to have count() of my table along with my result
i have achieved this with sub-query but for me cost of query matters that's why i am tired
to calculate count() along with my existing query.
How to add a column with existing record which calculate count of all records in table.?
I will attach my output
WITH survey AS (
SELECT
*
FROM
(
SELECT
student_id,
performance,
teacher_behaviour,
syllabus,
survey_id
FROM
survey_feedback
WHERE
survey_id = 1
GROUP BY
student_id,
performance,
teacher_behaviour,
syllabus,
survey_id
) UNPIVOT ( star
FOR q
IN ( performance AS 'PERFORMANCE',
teacher_behaviour AS 'TEACHER_BEHAVIOUR',
syllabus AS 'SYLLABUS' ) )
ORDER BY
1,
2
)
SELECT
*
FROM
survey PIVOT (
COUNT ( student_id )
FOR star
IN ( 1, 2, 3, 4, 5 )
)
ORDER BY
q;
Output is
1 PERFORMANCE 0 1 2 2 1
1 SYLLABUS 2 2 2 0 0
1 TEACHER_BEHAVIOUR 2 0 1 1 2
Desired Output is
1 PERFORMANCE 0 1 2 2 1 6 <-Want this total count of table
1 SYLLABUS 2 2 2 0 0 6
1 TEACHER_BEHAVIOUR 2 0 1 1 2 6

SQL left join - and after on clause is not working

I have a scenario in left join of SQL which is not generating required output which i need. Following is description in tabular form and my tried queries,
Table A
A_ID // PK OF TABLE A
IS_ACTIVE // VALUE=1 OR 0
Table B
B_ID // PK OF TABLE B
A_ID // FK OF TABLE A IN TABLE B
Sample Records of Table A
A_ID IS_ACTIVE
1 1
2 0
3 1
4 0
5 0
Sample Records of Table B
B_ID A_ID
1 1
2 1
3 4
4 4
5 4
6 4
Select * from A left join B on A.A_ID=B.A_ID
A_ID IS_ACTIVE B_ID A_ID
1 1 1 1
1 1 2 1
2 0 NULL NULL
3 1 NULL NULL
4 0 3 4
4 0 4 4
4 0 5 4
4 0 6 4
5 0 NULL NULL
Select * from A left join B on A.A_ID=B.A_ID and A.IS_ACTIVE=0
Following output is the actual output of above query with no effect to records by adding AND is_active=0 after ON clause.
A_ID IS_ACTIVE B_ID A_ID
1 1 1 1
1 1 2 1
2 0 NULL NULL
3 1 NULL NULL
4 0 3 4
4 0 4 4
4 0 5 4
4 0 6 4
5 0 NULL NULL
Following output is the required output which i need to solve my problem.
A_ID IS_ACTIVE B_ID A_ID
1 1 NULL NULL
1 1 NULL NULL
2 0 NULL NULL
3 1 NULL NULL
4 0 3 4
4 0 4 4
4 0 5 4
4 0 6 4
5 0 NULL NULL
I am facing problem in getting exact records which are required.
I need all records from Table A and matching records from Table B but
those records of Table B which are equal to is_active=0 of Table A.
Note : Query should show all records of Table A
Please help me how can i get this scenario in Left Join of SQL.
I tried your examples as code. And I get the result you needed. What is the problem?
CREATE TABLE #a(a_id int, is_active bit)
CREATE TABLE #b(b_id int, a_id int)
INSERT INTO #a(a_id,is_active)
VALUES(1,1),(2,0),(3,1),(4,0),(5,0)
INSERT INTO #b(b_id,a_id)
VALUES(1,1),(2,1),(3,4),(4,4),(5,4),(6,4)
SELECT *
FROM #a as a
LEFT JOIN #b as b
ON a.a_id = b.a_id
AND a.is_active = 0
DROP TABLE #a
DROP TABLE #b
Have you tried:
Select * from A left join B on A.A_ID=B.A_ID
Where A.IS_ACTIVE=0

Adding non existing data to SQL query

My SQL query returns the following result (screenshot):
x y count
----------- ----------- -----------
1 1 10
1 2 2
2 4 3
2 5 5
4 1 5
5 1 8
what i want is x, y should always contain 1 to 5 values, even if the query doesn't return them, in the above scenario x is missing 3. How to add the missing values here that are between 1 & 5.
Thanks in Advance
First you need to generate the desired data. You can use a table of numbers for this. Use CROSS JOIN to generate all possible combinations of two tables. Finally, OUTER JOIN the generated data with your table.
In the following query I have used union to build a list of numbers instead of fetching them from a table. But the idea remains same:
SELECT XList.x, YList.y, #temp.count
FROM (
SELECT 1 AS x UNION ALL
SELECT 2 UNION ALL
SELECT 3 UNION ALL
SELECT 4 UNION ALL
SELECT 5
) AS XList
CROSS JOIN (
SELECT 1 AS y UNION ALL
SELECT 2 UNION ALL
SELECT 3 UNION ALL
SELECT 4 UNION ALL
SELECT 5
) AS YList
LEFT JOIN #temp ON XList.x = #temp.x AND YList.y = #temp.y
Result:
x y count
----------- ----------- -----------
1 1 10
2 1 NULL
3 1 NULL
4 1 5
5 1 8
1 2 2
2 2 NULL
3 2 NULL
4 2 NULL
5 2 NULL
1 3 NULL
2 3 NULL
3 3 NULL
4 3 NULL
5 3 NULL
1 4 NULL
2 4 3
3 4 NULL
4 4 NULL
5 4 NULL
1 5 NULL
2 5 5
3 5 NULL
4 5 NULL
5 5 NULL
You can do it this way:
select t1.x, t2.y, s.count from
(values(1),(2),(3),(4),(5)) t1(x) cross join
(values(1),(2),(3),(4),(5)) t2(y)
left join #temp s on t1.x = s.x and t2.y = s.y