SQL Subtract the values of two resultsets - sql

Is there an operator eavailable similar to UNION that will allow one query's resultset to be subtracted from another?
eg:
Result of a UNION
2 3 2 6 1 2 6 3 7
1 3 5 2 7 8 4 3 2
Result of potential subtraction operator
1 0 -3 4 -6 -6 2 0 5

You case is much simpler: just subtract one column from another
CREATE TABLE #A
(
col1 INT NOT NULL
,col2 INT NOT NULL
);
INSERT INTO #A (col1,col2)
VALUES
(2,1)
,(3,3)
,(2,5)
,(6,2)
,(1,7)
,(2,8)
,(6,4)
,(3,3)
,(7,2)
SELECT (col1 - col2) AS result
FROM #A;
DROP TABLE #A;
Original answer
So if I understand you correctly you need to Subtract two one dimensional matrixes. Sql Server is not really the best tool to do such a math, but here is the example how you can achieve your goal. The idea is simple: introduce indexes (i,j) and join by them (you can skip j since you matrix is one-dimensional, the example works for two-dimensional arrays):
CREATE TABLE #A
(
element_value INT NOT NULL
,i INT NOT NULL
,j INT NOT NULL
,PRIMARY KEY (i, j)
);
CREATE TABLE #B
(
element_value INT NOT NULL
,i INT NOT NULL
,j INT NOT NULL
,PRIMARY KEY (i, j)
);
INSERT INTO #A (element_value,i,j)
VALUES
(2,1,1)
,(3,1,2)
,(2,1,3)
,(6,1,4)
,(1,1,5)
,(2,1,6)
,(6,1,7)
,(3,1,8)
,(7,1,9)
INSERT INTO #B (element_value,i,j)
VALUES
(1,1,1)
,(3,1,2)
,(5,1,3)
,(2,1,4)
,(7,1,5)
,(8,1,6)
,(4,1,7)
,(3,1,8)
,(2,1,9)
SELECT (A.element_value - B.element_value) AS result
FROM #A AS A,#B AS B
WHERE A.i = B.i
AND A.j = B.j;
DROP TABLE #A;
DROP TABLE #B;

Related

Insert from select on same table and store old and new identity values in separate table

Temporary table:
declare #Temp_Table table
(
newSID int,
oldSID int
)
Database table: Solutions
Solutions:
* 1 solution1 111
* 2 solution2 111
* 3 solution3 111
After insert,
* 1 solution1 111
* 2 solution2 111
* 3 solution3 111
* 4 solution1 222
* 5 solution2 222
* 6 solution3 222
temp table Expected
oldsID NewSID
* 1 4
* 2 5
* 3 6
This table has SID (identity), SName and cnumber.
Now I want to select some rows from the Solutions table and insert their values into same table.
When inserting each row I want to store the old identity value and new identity value in the temporary table (#Temp_Table).
Please help me with this.
The trick is to use merge instead of a regular insert into..select, since with merge you can use data from both the source and the target in the output clause.
First, create and populate sample table (Please save us this step in your future questions):
CREATE TABLE Solutions
(
SolutionID int identity (1,1),
SolutionName varchar(10),
ClientNumber int
)
INSERT INTO Solutions (SolutionName, ClientNumber) VALUES
('solution1', 111),
('solution2', 111),
('solution3', 111)
Then, declare the mapping table:
DECLARE #Temp_MasterSolutionsTable AS TABLE
(
newSolutionID int,
oldSolutionID int
)
Next, Copy the records you want:
MERGE INTO Solutions USING
(
SELECT SolutionID, SolutionName, ClientNumber
FROM Solutions
--WHERE CONDITION -- I'm guessing you will need a where clause here
) AS s ON 1 = 0 -- Always not matched
WHEN NOT MATCHED THEN
INSERT (SolutionName, ClientNumber)
VALUES (s.SolutionName, s.ClientNumber)
-- and here is where the magic happens
OUTPUT Inserted.SolutionID, s.SolutionID
INTO #Temp_MasterSolutionsTable (newSolutionID, oldSolutionID);
See a live demo on rextester.

Adding a Row Number to a Temp Table in Stored Procedure

I need to get one column from one table and put it in a temp table but also add another column to the temp table that would be the row number but I am not sure how to do that.
The basic problem I have is I have a table of communities and a table of sales and I need to go through the sales table and count how many were in each community. Then if a community has more than 5 then to increment a variable that signifies how many models made quota. My thought was to have a temp table that has each community in it alone with a row number and loop through that based on that row number through the sales table to make sure that I check each sale with each community.
Thanks for the input!
You can use IDENTITY on a #temp table.
IF OBJECT_ID('tempdb..#TableOne') IS NOT NULL
begin
drop table #TableOne
end
CREATE TABLE #TableOne
(
SurrogateKeyIDENTITY int not null IDENTITY (1,1) ,
NameOf varchar(12)
)
Insert into #TableOne (NameOf)
Select Alpha From
(
Select 'A' as Alpha UNION ALL Select 'Y' as Alpha UNION ALL Select 'B' as Alpha UNION ALL Select 'Z' as Alpha UNION ALL Select 'C' as Alpha
) as derived1
Order by Alpha
select * from #TableOne
IF OBJECT_ID('tempdb..#TableOne') IS NOT NULL
begin
drop table #TableOne
end
Output:
SurrogateKeyIDENTITY NameOf
1 A
2 B
3 C
4 Y
5 Z
You can use this :
CREATE TABLE #TableOne
(
SurrogateKeyIDENTITY int IDENTITY (1,1) ,
NameOf varchar(12)
)

Random Function behavior in SELECT query in SQL Server

I have a written a random function dbo.UDF_Q_RandomNumber() that generates a floating type random number between 0 and 1.
DECLARE #upper = 10
DECLARE #lower = 1
SELECT
ROUND(CAST((#lower + (#upper - #lower) * dbo.UDF_Q_RandomNumber()) AS INT), 0)
The above code generates a random number between 1 and 10.
Now I created a temporary table #tempTable with 10 rows in it with columns Id and Number.
Id Number
1 1
2 2
3 3
4 4
5 5
6 6
7 7
8 8
9 9
10 10
SQL query:
CREATE TABLE #tempTable(Id INT, Number INT)
INSERT INTO #tempTable VALUES (1,1)
INSERT INTO #tempTable VALUES (2,2)
INSERT INTO #tempTable VALUES (3,3)
INSERT INTO #tempTable VALUES (4,4)
INSERT INTO #tempTable VALUES (5,5)
INSERT INTO #tempTable VALUES (6,6)
INSERT INTO #tempTable VALUES (7,7)
INSERT INTO #tempTable VALUES (8,8)
INSERT INTO #tempTable VALUES (9,9)
INSERT INTO #tempTable VALUES (10,10)
DECLARE #maxCount INT;
SELECT #maxCount= COUNT(1) FROM #tempTable
SELECT * FROM #tempTable
SELECT Number
FROM #tempTable
WHERE Id = ROUND(CAST((1+(#maxCount-1)*dbo.UDF_Q_RandomNumber())AS INT),0)
DROP TABLE #tempTable
Here the query
SELECT Number
FROM #tempTable
WHERE Id = ROUND(CAST((1+(#maxCount-1)*dbo.UDF_Q_RandomNumber()) AS INT), 0)
Sometimes it returns 2 rows and sometimes null which should not come as Id selected is between 1 and 10 (the rows in temptable) and every Id has value too.
Please help .
Without seeing the function, it's hard to say, but I suspect your function is non-deterministic, so it gets interpreted for each row of the table.
If you use rand() it only returns one row
SELECT Number FROM #tempTable WHERE Id= ROUND(CAST((1+(#maxCount-1)*rand())AS INT),0)
Alternatively, if you just want a random #n rows...
select top (#n) * from #tempTable order by newid()

MySQL: Is it possible to return a "mixed" dataset?

I'm wondering if there's some clever way in MySQL to return a "mixed/balanced" dataset according to a specific criterion?
To illustrate, let's say that there are potential results in a table that can be of Type 1 or Type 2 (i.e. a column has a value 1 or 2 for each record). Is there a clever query that would be able to directly return results alternating between 1 and 2 in sequence:
1st record is of type 1,
2nd record is of type 2,
3rd record is of type 1,
4th record is of type 2,
etc...
Apologies if the question is silly, just looking for some options. Of course, I could return any data and do this in PHP, but it does add some code.
Thanks.
Something like this query should do:
Select some_value, x, c
From
(
Select
some_value, x,
Case When x=1 Then #c1 Else #c2 End As c,
#c1 := Case When x=1 Then #c1+2 Else #c1 End As c1,
#c2 := Case When x=2 Then #c2+2 Else #c2 End As c2
From test_data, (Select #c1:=0, #c2:=1) v
Order By some_value
) sub
Order By c
It assigns unique even numbers to x=0, and odd numbers to x=1, and uses these values as sort criteria.
It returns
some_value x c
A 1 0
X 2 1
B 1 2
Y 2 3
C 1 4
Z 2 5
for the following test-data:
Create Table test_data (
some_value VARCHAR(10),
x INT
);
Insert Into test_data Values('A', 1);
Insert Into test_data Values('B', 1);
Insert Into test_data Values('C', 1);
Insert Into test_data Values('Z', 2);
Insert Into test_data Values('Y', 2);
Insert Into test_data Values('X', 2);
Within the alternating rule values are sorted by some_value, you can change this in the inner select, or add your conditions there.
If there are more values of a certain type (1 or 2), you get them after the rest (1 2 1 2 2 2).
You can use IF function as a part of your SELECT statement to change columns, but I'm not sure how to make is alternate automatically between two columns. If you however find proper condition this will work for you
SELECT IF(condition, first_column, second_column) FROM your_table
first_column and second_column can be of different type, for example:
SELECT IF(id > 10, name, status_id) FROM clients
works well when name is a VARCHAR and status_id is an INT

T-Sql Query - Get Unique Rows Across 2 Columns

I have a set of data, with columns x and y. This set contains rows where, for any 2 given values, A and B, there is a row with A and B in columns x and y respectivly and there will be a second row with B and A in columns x and y respectivly.
E.g
**Column X** **Column Y**
Row 1 A B
Row 2 B A
There are multiple pairs of data in
this set that follow this rule.
For every row with A, B in Columns
X and Y, there will always be a
row with B, A in X and Y
Columns X and Y are of type int
I need a T-Sql query that given a set with the rules above will return me either Row 1 or Row 2, but not both.
Either the answer is very difficult, or its so easy that I can't see the forest for the trees, either way it's driving me up the wall.
Add to your query the predicate,
where X < Y
and you can never get row two, but will always get row one.
(This assumes that when you wrote "two given values" you meant two distinct given values; if the two values can be the same, add the predicate where X <= Y (to get rid of all "reversed" rows where X > Y) and then add a distinct to your select list (to collapse any two rows where X == Y into one row).)
In reply to comments:
That is, if currently your query is select foo, x, y from sometable where foo < 3; change it to select foo, x, y from sometable where foo < 3 and x < y;, or for the the second case (where X and Y are not distinct values) select distinct foo, x, y from sometable where foo < 3 and x <= y;.
This should work.
Declare #t Table (PK Int Primary Key Identity(1, 1), A int, B int);
Insert into #t values (1, 2);
Insert into #t values (2, 1);
Insert into #t values (3, 4);
Insert into #t values (4, 3);
Insert into #t values (5, 6);
Insert into #t values (6, 5);
Declare #Table Table (ID Int Primary Key Identity(1, 1), PK Int, A Int, B Int);
Declare #Current Int;
Declare #A Int;
Insert Into #Table
Select PK, A, B
From #t;
Set #Current = 1;
While (#Current <= (Select Max(ID) From #Table) Begin
Select #A = A
From #Table
Where ID = #Current;
If (#A Is Not Null) Begin
Delete From #Table Where B = #A;
If ((Select COUNT(*) From #Table Where A = #A) > 1) Begin
Delete From #Table Where ID = #Current;
End
End
Set #A = Null;
Set #Current = #Current + 1;
End
Select a.*
From #tAs a
Inner Join #Table As b On a.PK = b.PK
SELECT O.X, O.Y
FROM myTable O
WHERE EXISTS (SELECT X, Y FROM myTable I WHERE I.X = O.Y AND I.Y = O.X)
I have not tried this. But, this should work.
To get the highest and lowest of each pair, you could use:
(X+Y+ABS(X-Y)) / 2 as High, (X+Y-ABS(X-Y)) / 2 as Low
So now use DISTINCT to get the pairs of them.
SELECT DISTINCT
(X+Y+ABS(X-Y)) / 2 as High, (X+Y-ABS(X-Y)) / 2 as Low
FROM YourTable