Query for relationships between rows - sql-server

I need to find a relation between multiple person in single table, for example I have the below table:
Guests Table
so I need by sql script to say Guest 123 and 456 they checked in together to the same hotel in the same time 80% and so on...
Kindly support.

It's a little complicated so I've broken it down into multiple subqueries for you using a CTE with a matched key.
This will produce a series of matched pairs - for the primary guest and secondary guest with ratios of how often they stay together rather than just check in.
Setup:
create table temp(
hotelID integer,
checkInDate date,
guestID integer
)
insert into temp values (101, '2020/06/01', 123)
insert into temp values (101, '2020/06/01', 456)
insert into temp values (102, '2020/06/15', 123)
insert into temp values (102, '2020/06/15', 456)
insert into temp values (103, '2020/06/30', 123)
insert into temp values (103, '2020/06/30', 456)
insert into temp values (104, '2020/07/15', 123)
insert into temp values (104, '2020/07/15', 789)
insert into temp values (105, '2020/07/01', 456)
insert into temp values (105, '2020/07/01', 789)
Query:
with keyCte as (
select
distinct cast(hotelID as varchar(3)) + cast(checkInDate as varchar(10)) as myKey,
guestID
from temp
)
select
guestPrime
, guestTwo
, instances as guestPrimeStays
, matches as guestTwoMatches
, cast(matches as float) / cast(instances as float) as hitRate
from (
select
guestID
, count(*) as instances
from keyCte
group by guestID
) sq3
join (
select
guestPrime
, guestTwo
, count(*) as matches
from (
select
keyCte.guestID as guestPrime
, kcte.guestID as guestTwo
from keyCte
join keyCte kcte on kcte.myKey = keyCte.myKey and kcte.guestID != keyCte.guestID
) sq
group by guestPrime, guestTwo
) sq2 on sq2.guestPrime = guestID

Related

Detect duplicate row within a batch - T-SQL

I have the following scenario:
I have a transaction, in which a batch of records is being sent from one table (source) to another(target). The transaction is defined within TRY-CATCH statements to detect errors. Having a PK constraint defined on the target table, I want to detect records/rows which violate the constraint, and then isolate these records into a separate table (duplicates). The TRY will detect the violation, however which T-SQL statement(s) can identify those rows and only isolate them?
Bellow a simplified script that identify duplicates on pk-values and extract only one recordset of a PK to the target table and the other to a duplicate table:
DROP TABLE IF EXISTS #source;
DROP TABLE IF EXISTS #target;
DROP TABLE IF EXISTS #duplicates;
CREATE TABLE #source ( pk INT, value INT )
INSERT INTO #source
VALUES (10, 100), (10, 101), (10, 102), (10, 103), (20, 200), (20, 201)
SELECT *
INTO #target
FROM ( SELECT PkRowId = ROW_NUMBER() OVER(PARTITION BY pk ORDER BY value), pk, value FROM #source ) AS sub
WHERE PkRowId = 1;
SELECT *
INTO #duplicates
FROM ( SELECT PkRowId = ROW_NUMBER() OVER(PARTITION BY pk ORDER BY value), pk, value FROM #source ) AS sub
WHERE PkRowId > 1;
SELECT * FROM #target;
SELECT * FROM #duplicates;
Which recordset will get PkRowId 1 you can control with ORDER BY if necessary.

Get max value from table and group by with column having comma separated value with different order or having more values

I am having a table like this along with data
CREATE TABLE temp (
`name` varchar(20),
`ids` varchar(20),
`value1` int,
`value2` int
);
INSERT INTO temp(`name`,`ids`, `value1`, `value2`) values
('A', '1,2', 10, 11),
('A', '2,1', 12, 100),
('A', '1,2,3', 20, 1),
('B', '6', 30, 10)
I need to get the max value by Name along with ids
I am using the following query to get the max value.
select name, ids, max(value1) as value1, max(value2) as value2
from temp
group by name,ids
The question has been tagged as Sybase ASE, but the 'create table and 'insert' commands are invalid in ASE so not sure if this is an issue of an incorrect tag or the wrong 'create table' and 'insert' commands ... so, assuming this is for a Sybase ASE database:
I'm assuming the desired output is to display those rows where value = max(value).
First we'll setup our test case:
create table mytab
(name varchar(20)
,ids varchar(20)
,value int)
go
insert into mytab (name,ids,value) values ('A', '1,2' , 10)
insert into mytab (name,ids,value) values ('A', '2,1' , 12)
insert into mytab (name,ids,value) values ('A', '1,2,3', 20)
insert into mytab (name,ids,value) values ('B', '6' , 30)
go
Here's one possible solution:
select t.name, t.ids, t.value
from mytab t
join (select name,max(value) as maxvalue from mytab group by name) dt
on t.name = dt.name
and t.value = dt.maxvalue
order by t.name
go
name ids value
-------------------- -------------------- -----------
A 1,2,3 20
B 6 30
The subquery/derived-table gives us the max(value) for each unique name. The main query then joins these name/max(value) pairs back to the main table to give us the desired rows (ie, where value = max(value)).
Tested on ASE 15.7 SP138.

How to update table when rows of one table are different from the other

I have a table table1 and a temporary table temp2. Temp2 contains updated values which i want to update in table1. So, for any rows that are different i want to update the values from Temp2 to table 1. I tried something like this but its not working.
update Role_Master set Role_Desc=Role_Descc , Role_Version_Number =Role_Version_Number+1,Role_Dept=Role_Deptt,Role_All_Clients=Role_All_Clientss,
Role_Admin=Role_Adminn,Role_Super_Admin=Role_Super_Adminn,Role_Modified_Date = GETDATE(),Role_Modified_By = 'T6086' FROM #TEMP1 where Role_ID in
(SELECT #TEMP1.Role_IDD FROM #TEMP1 LEFT JOIN Role_Master ON (#TEMP1.Role_Descc = Role_Master.Role_Desc and #Temp1.Role_Deptt=Role_Master.Role_Dept)
WHERE Role_Master.Role_Desc is null and Role_Master.Role_Dept IS NULL)
hard to help you without knowing the schema of the two tables ... but it should be possible to join the two tables and decide by a where condition which rows to update ... check out this simple example ... maybe it helps
create table #temp1 (id int, val nvarchar(100))
create table #temp2 (id int, val nvarchar(100))
insert into #temp1 (id, val) values (1, 'eins')
insert into #temp1 (id, val) values (2, 'eins')
insert into #temp1 (id, val) values (3, 'eins')
insert into #temp2 (id, val) values (1, 'zwei')
insert into #temp2 (id, val) values (2, 'eins')
insert into #temp2 (id, val) values (3, 'eins')
update #temp1 set #temp1.val = b.val
from #temp1 a join #temp2 b on a.id = b.id
where a.val <> b.val
select ##rowcount -- returns 1 because 1 row was updated
select * from #temp1

How do I find records out of order - SQL?

Let's say I have a table with an ID Identity column, some data, and a datestamp. Like this:
1 data 5/1/2013 12:30
2 data 5/2/2013 15:32
3 data 5/2/2013 16:45
4 data 5/3/2013 9:32
5 data 5/5/2013 8:21
6 data 5/4/2013 9:36
7 data 5/6/2013 11:42
How do I write a query that will show me the one record that is timestamped 5/4? The table has millions of records. I've done some searching, but I don't know what to call what I'm searching for. :/
declare #t table(id int, bla char(4), timestamp datetime)
insert #t values
(1,'data','5/1/2013 12:30'),
(2,'data','5/2/2013 15:32'),
(3,'data','5/2/2013 16:45'),
(4,'data','5/3/2013 9:32'),
(5,'data','5/5/2013 8:21'),
(6,'data','5/4/2013 9:36'),
(7,'data','5/6/2013 11:42')
select timestamp
from
(
select rn1 = row_number() over (order by id),
rn2 = row_number() over (order by timestamp), timestamp
from #t
) a
where rn1 not in (rn2, rn2-1)
in 2008 r2, this would be a way
DECLARE #Table AS TABLE
(id INT , ladate DATETIME)
INSERT INTO #Table VALUES (1, '2013-05-01')
INSERT INTO #Table VALUES (2, '2013-05-02')
INSERT INTO #Table VALUES (3, '2013-05-03')
INSERT INTO #Table VALUES (4, '2013-05-05')
INSERT INTO #Table VALUES (5, '2013-05-04')
INSERT INTO #Table VALUES (6, '2013-05-06')
INSERT INTO #Table VALUES (7, '2013-05-07')
INSERT INTO #Table VALUES (8, '2013-05-08')
--I added the records in the sort order but if not just make sure you are sorted in the query
SELECT t2.ladate FROM #Table T1
INNER JOIN #Table T2 ON T1.Id = T2.Id + 1
INNER JOIN #Table t3 ON t2.id = t3.id + 1
WHERE t3.ladate < t2.ladate AND t2.ladate > t1.ladate
-- I made the assumption that your Id are all there, 1,2,3,4,5.... none missing... if there are rownumbers missing, you can use row_number()

Smart Many to Many Query

I have a list of item descriptions in a c# application. What I want is when I select
1 or 2 or more item descriptions of that list (checkbox list) to predict via an sql query to a many to many table what my item is (minimizing each time the possible predictions);
For example
item 1: white,green,blue
item 2: white,red,cyan
item 3: red,blue,purple
user should select from a check list
white->query will return item 1,2
white&green->query will return only item 1
From your humble description of the problem, I suppose you want something like this:
CREATE TABLE items (
item_id INT NOT NULL PRIMARY KEY IDENTITY(1,1),
name VARCHAR(100) NOT NULL
)
CREATE TABLE colors (
color_id INT NOT NULL PRIMARY KEY IDENTITY(1,1),
name VARCHAR(100) NOT NULL
)
CREATE TABLE items_colors (
item_id INT NOT NULL FOREIGN KEY REFERENCES items(item_id),
color_id INT NOT NULL FOREIGN KEY REFERENCES colors(color_id),
PRIMARY KEY(item_id, color_id),
)
INSERT INTO items(name) VALUES ('item 1')
INSERT INTO items(name) VALUES ('item 2')
INSERT INTO items(name) VALUES ('item 3')
INSERT INTO colors(name) VALUES ('white')
INSERT INTO colors(name) VALUES ('green')
INSERT INTO colors(name) VALUES ('blue')
INSERT INTO colors(name) VALUES ('red')
INSERT INTO colors(name) VALUES ('cyan')
INSERT INTO colors(name) VALUES ('purple')
INSERT INTO items_colors(item_id, color_id) VALUES (1, 1)
INSERT INTO items_colors(item_id, color_id) VALUES (1, 2)
INSERT INTO items_colors(item_id, color_id) VALUES (1, 3)
INSERT INTO items_colors(item_id, color_id) VALUES (2, 1)
INSERT INTO items_colors(item_id, color_id) VALUES (2, 4)
INSERT INTO items_colors(item_id, color_id) VALUES (2, 5)
INSERT INTO items_colors(item_id, color_id) VALUES (3, 3)
INSERT INTO items_colors(item_id, color_id) VALUES (3, 4)
INSERT INTO items_colors(item_id, color_id) VALUES (3, 6)
SELECT i.*
FROM items i
WHERE 2 = (
SELECT COUNT(*)
FROM items_colors ic
JOIN colors c
ON ic.color_id = c.color_id
WHERE i.item_id = ic.item_id
AND c.name IN ('white', 'green')
)
Within "IN" clause you should provide list of values that user has selected in the UI (you have to build list of parameters dynamically). You also have to provide number of elements that user has selected ("2" in my example solution).
So the query in application will look like this:
SELECT i.*
FROM items i
WHERE #count = (
SELECT COUNT(*)
FROM items_colors ic
JOIN colors c
ON ic.color_id = c.color_id
WHERE i.item_id = ic.item_id
AND c.name IN (#color1, #color2, ..., #colorN)
)
(Where #count is the number of #colorX parameters.)

Resources