SQL Hide/Show rows based on row count from another table - sql

I have a SQL question. I have two tables, tableA has 4 records, tableB has 0 records right now, but will go over 200 total records. I was wondering if there is away to hide the last two records of tableA if tableB is under 200 records?
What I got so far is very simple
SELECT
id, dateSlot, timeSlot
FROM
tableA a
INNER JOIN
tableB b ON a.id = b.dateTimeSlotId;
I just don't know how to hide records based on another tables total records.
Can anyone help?

It is only an idea. if the tables are not symmetric you need to improve the logic.
declare #tableA table (id int)
declare #tableB table (dateTimeSlotId int , dateSlot date, timeSlot time)
insert #tableA values (1),(2),(3),(4),(5),(6),(7)
insert #tableB values
(1,'20170801', '00:00'),
(2,'20170802', '00:01'),
(3,'20170803', '00:02'),
(4,'20170804', '00:03'),
(5,'20170805', '00:04'),
(6,'20170806', '00:05'),
(7,'20170807', '00:06')
;with cte as(
SELECT ROW_NUMBER() over (order by id) rNumber, id, dateSlot, timeSlot
FROM #tableA a INNER JOIN
#tableB b
ON a.id = b.dateTimeSlotId)
SELECT id, dateSlot, timeSlot
FROM cte where rNumber <= (SELECT case when Count(1) >= 200 then Count(1) -2 else Count(1) end from #tableB)

Related

Join and select column with max value

I am working on two tables in Oracle, TABLE_A containing unique IDs and Balance (number). TABLE_B shows, for the same IDs, the specific transactions and contains the following fields: IDs (not unique), BAL, Sequence_number.
I want to check that TABLE_A.Balance is always equal to TABLE_B.Balance having Max(Sequence_number).
So I expect to have just one row for each ID.
I've tried the following, yet it does not return a unique row for each ID but multiples. Why is that?
Select a.ID, a.Balance,b.Balance, b.sequence_number From TABLE_A a Inner join (select ID, Balance, max(sequence_number) as sequence_number from TABLE_B group by ID, Balance) b On a.ID = B.ID Group by a.ID, a.Balance, b.Balance, b.sequence_number
TABLE_A
ID_______Balance
1_______10
2_______15
3_______50
TABLE_B
ID____Balance____Sequence_number
1_______19_______1
1_______75_______2
1_______10_______3
2_______39_______1
2_______15_______2
3_______120_______1
3_______89_______2
3_______57_______3
3_______50_______4
You can use window functions:
select a.*, b.balance
from a left join
(select b.*,
row_number() over (partition by id order by sequence_number desc) as seqnum
from b
) b
on b.id = a.id and b.seqnum = 1;
I'm not quite sure what you want to compare, but this returns every row in a with the row in b that has the highest sequence number.
You can use row_number()over() window function to get the row having ID wise highest sequence_number.
Schema:
create table TABLE_A(ID int, Balance int);
insert into TABLE_A values(1,10);
insert into TABLE_A values(2,15);
insert into TABLE_A values(3,50);
create table TABLE_B (ID int , Balance int,Sequence_number int);
insert into TABLE_B values(1,19,1);
insert into TABLE_B values(1,75,2);
insert into TABLE_B values(1,10,3);
insert into TABLE_B values(2,39,1);
insert into TABLE_B values(2,15,2);
insert into TABLE_B values(3,120,1);
insert into TABLE_B values(3,89,2);
insert into TABLE_B values(3,57,3);
insert into TABLE_B values(3,50,4);
GO
Query:
with cte as
(
select id, balance, sequence_number, row_number()over (partition by id order by sequence_number desc)rnk from table_b
)
Select a.ID, a.Balance,b.Balance, b.sequence_number From TABLE_A a
Inner join cte b on a.id=b.id and rnk=1;
GO
Output:
ID
Balance
Balance
sequence_number
1
10
10
3
2
15
15
2
3
50
50
4
db<>fiddle here

SQL Full Outer Join without duplicates with like condition

Following are two tables.
I want to find and join records between two tables with having value -1 or +1.
But in that case it returns me duplicate records also.
How can i get the result without duplicate records?
drop table if exists #A
CREATE TABLE #A(ID float, Category varchar(10), Amount float )
insert into #A values
(1,'A',150.4),
(2,'A',151.0),
(3,'A',149.8),
(4,'A',165.0),
(5,'A',165.0)
drop table if exists #B
CREATE TABLE #B(BID float, BCategory varchar(10), BAmount float )
insert into #B values
(95,'A',151),
(101,'A',150),
(115,'A',165.0),
(118,'A',165.0)
i have tried following query, which returns duplicates.
select *
from
(select
ID, category, Amount,
row_number() over (partition by category, Amount order by category, Amount) as Sr
from #A) A
full outer join
(select
BID, Bcategory, BAmount,
row_number() over (partition by Bcategory, BAmount order by Bcategory, BAmount) as Sr
from #B) B on a.category = b.bCategory
and a.amount between b.bamount - 1 and b.BAmount + 1
and a.sr = b.sr
Logic: How the current user is mapping manually:-
First, try to Exact match (category and amount) with another table.
Then whatever left try to match Category and Amount with (+/- 1) of TableB.
So 149.8 or 150.4 of A, both any can join with 150 of B. Since only one (150) in Table B is left and 151 already assigned to 151 under exact match, one record of A will be join to null.
Let's say, since 150.4 is appearing first in tableA it can go with 150 of TableB.
And 149.8 will remain unmatched. Practically user does not mind to match with either or. Important is, any one row (150.4 or 149.8) shall match to null. Problem with left or full outer join is, 150 of B is being assigned to both (149.8 and 150.4).
If you want unique record we need to mapped relation between the table
Table Definition
drop table if exists #A
CREATE TABLE #A(ID float, Category varchar(10), Amount float )
insert into #A values
(1,'A',150.4),
(2,'A',151.0),
(3,'A',149.8),
(4,'A',165.0),
(5,'A',165.0)
drop table if exists #B
CREATE TABLE #B(AID float,BID float, BCategory varchar(10), BAmount float )
insert into #B values
(2,95,'A',151),
(1,101,'A',150),
(4,115,'A',165.0),
(5,118,'A',165.0)
Query
SELECT * FROM #A A
LEFT JOIN #B B ON A.ID = B.AID
Other way
select *
from
(select
ID, category, Amount,
row_number() over (partition by category, Amount order by category, Amount) as Sr
from #A) A
full outer join
(select
AID,BID, Bcategory, BAmount,
row_number() over (partition by Bcategory, BAmount order by Bcategory, BAmount) as Sr
from #B) B on a.category = b.bCategory
and a.amount between b.bamount - 1 and b.BAmount + 1
and a.sr = b.sr AND A.ID = B.AID
OutPut result

How to get the records of table A, which are in one row in table B

SELECT ClaimID, CPTCode FROM TABLEA
ClaimId CPTCode
**60 62000**
**60 0213T**
60 99383
60 93230
60 96372
SELECT cpt1,CPT2 FROM TABLEB
cpt1 CPT2
**62000 0213T**
**62000 0230T**
62000 0216T
62000 0228T
SELECT the record from tableA only that which is at same row in tableB
Result should be
60 62000
60 0213T
I think this does what you want:
select ClaimID, CPTCode
from tablea a
where exists (select 1
from tableb b
where b.cpt1 = a.cptcode
) or
exists (select 1
from tableb b
where b.cpt2 = a.cptcode
);
This query can take advantage of two indexes: tableb(cpt1) and tableb(cpt2).
You can write this as:
select ClaimID, CPTCode
from tablea a
where exists (select 1
from tableb b
where a.cptcode in (b.cpt1, b.cpt2)
);
However, this version is much harder to optimize.
try this-
select obj.ClaimID, obj.CPTCode from (
select row_number() as row_noA, ClaimID, CPTCode FROM TABLEA
join
select row_number() as row_noB, cpt1,CPT2 FROM TABLEB
on TABLEA.CPTCode = TABLEB.CPT2 and TABLEA.row_noA = TABLEB.row_noB
)obj
join two tables and match each row using same row number and get the output

Find Modified/New/Deleted Records Between Two Tables

I want to find new, modified and deleted records in one table (tableA) by comparing it to another table (tableB). Both tables are of the same schema and has a unique ID field.
In my situation, tableA is originally the same as tableB but it has been edited by some external organisation and once they have done their edits, they send the table back via ZIP file, and we re-populate (truncate and insert) that data to tableA. So I want to find out what records have changed in tableA. I am using SQL Server 2012.
I can get new and modified records with the "except" keyword:
select * from tableA
except
select * form tableB
(Let's call the above results ResultsA)
I can also get deleted and modified records:
select * from tableB
except
select * form tableA
(Let's call the above results ResultsB)
The problem is, both ResultsA and ResultsB have the same records that have been modified/edited. So the modified/edited records are doubled up. I can use inner join or intersect on ResultsA and ResultsB to get just the modified records (call this results ResultsC). But then I will need to use join/except again between ResultsA and ResultsC to get just the new records, and join/except again between ResultsB and ResultsC to get just the deleted records... I tried this and this but they are not working for me.
Obviously this is not good. Are there any elegant and simpler ways to find out the records that have been deleted, modified or added in tableA compared to tableB?
How about:
-- DELETED
SELECT B.*, 'DELETED' AS 'CHANGE_TYPE'
FROM TableB B
LEFT JOIN TableA A ON B.PK_ID = A.PK_ID
WHERE A.PK_ID IS NULL
UNION
-- NEW
SELECT A.*, 'NEW' AS 'CHANGE_TYPE'
FROM TableA A
LEFT JOIN TableB B ON B.PK_ID = A.PK_ID
WHERE B.PK_ID IS NULL
UNION
-- MODIFIED
SELECT B.*, 'MODIFIED' AS 'CHANGE_TYPE'
FROM (
SELECT * FROM TableA
EXCEPT
SELECT * FROM TableB
) S1
INNER JOIN TableB B ON S1.PK_ID = B.PK_ID;
Not exactly elegant, but it works.
Based on what i understood i came up with the following solution.
DECLARE #tableA TABLE (ID INT, Number INT)
DECLARE #tableB TABLE (ID INT, Number INT)
INSERT INTO #tableA VALUES
(1,10),
(2,20),
(3,30),
(4,40)
INSERT INTO #tableB VALUES
(1,11),
(2,20),
(4,40),
(5,50)
SELECT *,'Modified or deleted' as 'Status' FROM
(
select * from #tableA
except
select * from #tableB
)a WHERE ID NOT IN
(
select ID from #tableB
except
select ID from #tableA
)
UNION
SELECT *,'New' as 'Status' FROM
(
select * from #tableB
except
select * from #tableA
)b WHERE ID NOT IN
(
SELECT ID FROM
(
select * from #tableA
except
select * from #tableB
)a WHERE ID NOT IN
(
select ID from #tableB
except
select ID from #tableA
)
)
You can use the OUTPUT clause:
Returns information from, or expressions based on, each row affected by an INSERT, UPDATE, or DELETE statement. These results can be returned to the processing application for use in such things as confirmation messages, archiving, and other such application requirements. Alternatively, results can be inserted into a table or table variable.
See the the following, sorry I don't have a practical code for you. But note the SQL output clause can be used to return any value from ‘inserted’ and ‘deleted’ (New value and Old value) tables when doing an insert or update. follow this for more info
declare #DBOrderItem table
(
OrderItemGuid UniqueIdentifier default newid(),
Name VarChar(100)
);
declare #PayloadOrderItem table
(
OrderItemGuid UniqueIdentifier default newid(),
Name VarChar(100)
);
insert into #DBOrderItem (Name) values ('Phone');
insert into #DBOrderItem (Name) values ('Laptop');
insert into #PayloadOrderItem
select top 1 * from #DBOrderItem;
insert into #PayloadOrderItem (Name) values ('Tablet');
select doi.OrderItemGuid,
doi.Name,
case when poi.OrderItemGuid is null then 'Delete' else 'Update' end ActionType
from #DBOrderItem doi
left join #PayloadOrderItem poi on doi.OrderItemGuid = poi.OrderItemGuid
union
select poi.OrderItemGuid,
poi.Name,
'Add' ActionType
from #PayloadOrderItem poi
left join #DBOrderItem doi on doi.OrderItemGuid = poi.OrderItemGuid
where doi.OrderItemGuid is null;
Another solution that works quite efficiently is to use a where not exists an intersect between the two tables. Its very compact.
SELECT
IsNull(tableB.ID,tableA.ID) as 'ID',
IsNull(tableB.Number,tableA.Number) as 'Number',
'Action' = CASE
WHEN tableB.ID IS NULL THEN 'Deleted'
WHEN tableA.ID IS NULL THEN 'Created'
ELSE 'Updated'
END
FROM tableA
FULL OUTER JOIN tableB
ON tableB.ID = tableA.ID
WHERE
NOT EXISTS (SELECT tableB.* INTERSECT SELECT tableA.*)
This keeps the table scans down to a minimum, and provides detection of new, deleted and changed records.
I put all three from here into fiddle, and its surprising how differently they all compile.
http://sqlfiddle.com/#!6/b1a5a/5
This one works without primary key also a bit more elegant .(in my opinion!)
WITh A AS (SELECT 1,2,3 FROM DUAL
UNION ALL
SELECT 1,3,2 FROM DUAL
UNION ALL
SELECT 1,3,1 FROM DUAL),
B AS (SELECT 1,3,2 FROM DUAL
UNION ALL
SELECT 1,2,3 FROM DUAL
UNION ALL
SELECT 1,3,5 FROM DUAL
)
,
C AS
(SELECT * FROM A
MINUS
SELECT * FROM B
),
D AS( SELECT * FROM b
MINUS
SELECT * FROM A)
SELECT C.* ,'Deleted' FROM c
UNION ALL
SELECT D.* ,'Added' FROM D

Join Tables with no Join Criteria

This seems so simple, but I just can't figure it out. I want to simply join 2 tables together. I don't care which values are paired with which. Using TSQL, here is an example:
declare #tbl1 table(id int)
declare #tbl2 table(id int)
insert #tbl1 values(1)
insert #tbl1 values(2)
insert #tbl2 values(3)
insert #tbl2 values(4)
insert #tbl2 values(5)
select * from #tbl1, #tbl2
This returns 6 rows, but what kind of query will generate this (just slap the tables side-by-side):
1 3
2 4
null 5
You can give each table row numbers and then join on the row numbers:
WITH
Table1WithRowNumber as (
select row_number() over (order by id) as RowNumber, id from Table1
),
Table2WithRowNumber as (
select row_number() over (order by id) as RowNumber, id from Table2
)
SELECT Table1WithRowNumber.Id, Table2WithRowNumber.Id as Id2
FROM Table1WithRowNumber
FULL OUTER JOIN Table2WithRowNumber ON Table1WithRowNumber.RowNumber = Table2WithRowNumber.RowNumber
Edit: Modiifed to use FULL OUTER JOIN, so you get all rows (with nulls).
Use Cross Join
Select * From tableA Cross Join TableB
But understand you will get a row in the output for every combination of rows in TableA with every Row in TableB...
So if Table A has 8 rows, and TableB has 4 rows, you will get 32 rows of data...
If you want any less than that, you have to specify some join criteria, that will filter out the extra rows from the output
Well, this will work:
Select A.ID, B.ID From
(SELECT ROW_NUMBER () OVER (ORDER BY ID) AS RowNumber, ID FROM Tbl2 ) A
full outer join
(SELECT ROW_NUMBER () OVER (ORDER BY ID) AS RowNumber, ID FROM Tbl1 ) B
on (A.RowNumber=B.RowNumber)
The SQL1 cross join applies here also.
Select *
From tableA, TableB