SQL Server find unique combinations - sql

I have a table
rate_id service_id
1 1
1 2
2 1
2 3
3 1
3 2
4 1
4 2
4 3
I need to find and insert in a table the unique combinations of sevice_ids by rate_id...but when the combination is repeated in another rate_id I do not want it to be inserted
In the above example there are 3 combinations
1,2 1,3 1,2,3
How can I query the first table to get the unique combinations?
Thanx!

Try doing something like this:
DECLARE #TempTable TABLE ([rate_id] INT, [service_id] INT)
INSERT INTO #TempTable
VALUES (1,1),(1,2),(2,1),(2,3),(3,1),(3,2),(4,1),(4,2),(4,3)
SELECT DISTINCT
--[rate_id], --include if required
(
SELECT
CAST(t2.[service_id] AS VARCHAR) + ' '
FROM
#TempTable t2
WHERE
t1.[rate_id] = t2.[rate_id]
ORDER BY
t2.[rate_id]
FOR XML PATH ('')
) AS 'Combinations'
FROM
#TempTable t1
I put the values in a table variable just for ease of testing the SELECT query.

Related

SQL Select Where Opposite Match Does Not Exist

Trying to compare between two columns and check if there are no records that exist with the reversal between those two columns. Other Words looking for instances where 1-> 3 exists but 3->1 does not exist. If 1->2 and 2->1 exists we will still consider 1 to be part of the results.
Table = Betweens
start_id | end_id
1 | 2
2 | 1
1 | 3
1 would be added since it is a start to an end with no opposite present of 3,1. Though it did not get added until the 3rd entry since 1 and 2 had an opposite.
So, eventually it will just return names where the reversal does not exist.
I then want to join another table where the number from the previous problem has its name installed on it.
Table = Names
id | name
1 | Mars
2 | Earth
3 | Jupiter
So results will just be the names of those that don't have an opposite.
You can use a not exists condition:
select t1.start_id, t1.end_id
from the_table t1
where not exists (select *
from the_table t2
where t2.end_id = t1.start_id
and t2.start_id = t1.end_id);
I'm not sure about your data volume, so with your ask, below query will supply desired result for you in Sql Server.
create table TableBetweens
(start_id INT,
end_id INT
)
INSERT INTO TableBetweens VALUES(1,2)
INSERT INTO TableBetweens VALUES(2,1)
INSERT INTO TableBetweens VALUES(1,3)
create table TableNames
(id INT,
NAME VARCHAR(50)
)
INSERT INTO TableNames VALUES(1,'Mars')
INSERT INTO TableNames VALUES(2,'Earth')
INSERT INTO TableNames VALUES(3,'Jupiter')
SELECT *
FROM TableNames c
WHERE c.id IN (
SELECT nameid1.nameid
FROM (SELECT a.start_id, a.end_id
FROM TableBetweens a
LEFT JOIN TableBetweens b
ON CONCAT(a.start_id,a.end_id) = CONCAT(b.end_id,b.start_id)
WHERE b.end_id IS NULL
AND b.start_id IS NULL) filterData
UNPIVOT
(
nameid
FOR id IN (filterData.start_id,filterData.end_id)
) AS nameid1
)

Pivot in SQL: count not working as expected

I have in my Oracle Responsys Database a table that contains records with amongst other two variables:
status
location_id
I want to count the number of records grouped by status and location_id, and display it as a pivot table.
This seems to be the exact example that appears here
But when I use the following request :
select * from
(select status,location_id from $a$ )
pivot (count(status)
for location_id in (0,1,2,3,4)
) order by status
The values that appear in the pivot table are just the column names :
output :
status 0 1 2 3 4
-1 0 1 2 3 4
1 0 1 2 3 4
2 0 1 2 3 4
3 0 1 2 3 4
4 0 1 2 3 4
5 0 1 2 3 4
I also gave a try to the following :
select * from
(select status,location_id , count(*) as nbreports
from $a$ group by status,location_id )
pivot (sum(nbreports)
for location in (0,1,2,3,4)
) order by status
but it gives me the same result.
select status,location_id , count(*) as nbreports
from $a$
group by status,location_id
will of course give me the values I want, but displaying them as a column and not as a pivot table
How can I get the pivot table to have in each cell the number of records with the status and location in row and column?
Example data:
CUSTOMER,STATUS,LOCATION_ID
1,-1,1
2,1,1
3,2,1
4,3,0
5,4,2
6,5,3
7,3,4
The table data types :
CUSTOMER Text Field (to 25 chars)
STATUS Text Field (to 25 chars)
LOCATION_ID Number Field
Please check if my understanding for your requirement is correct, you can do vice versa for the location column
create table test(
status varchar2(2),
location number
);
insert into test values('A',1);
insert into test values('A',2);
insert into test values('A',1);
insert into test values('B',1);
insert into test values('B',2);
select * from test;
select status,location,count(*)
from test
group by status,location;
select * from (
select status,location
from test
) pivot(count(*) for (status) in ('A' as STATUS_A,'B' as STATUS_B))

SQL Server match and count on substring

I am using SQL Server 2008 R2 and have a table like this:
ID Record
1 IA12345
2 IA33333
3 IA33333
4 IA44444
5 MO12345
I am trying to put together some SQL to return the two rows that contain IA12345 and MO12345. So, I need to match on the partial string of the column "Record". What is complicating my SQL is that I don't want to return matches like IA33333 and IA33333. Clear as mud?
I am getting twisted up in substrings, group by, count and the like!
SELECT ID, Record FROM Table WHERE Record LIKE '%12345'
Select *
from MyTable
where Record like '%12345%'
This will find repeating and/or runs. For example 333 or 123 or 321
Think of it as Rummy 500
Declare #YourTable table (ID int,Record varchar(25))
Insert Into #YourTable values
( 1,'IA12345'),
( 2,'IA33333'),
( 3,'IA33333'),
( 4,'IA44444'),
( 5,'MO12345'),
( 6,'M785256') -- Will be excluded because there is no pattern
Declare #Num table (Num int);Insert Into #Num values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9)
Select Distinct A.*
From #YourTable A
Join (
Select Patt=replicate(Num,3) from #Num
Union All
Select Patt=right('000'+cast((Num*100+Num*10+Num)+12 as varchar(5)),3) from #Num where Num<8
Union All
Select Patt=reverse(right('000'+cast((Num*100+Num*10+Num)+12 as varchar(5)),3)) from #Num where Num<8
) B on CharIndex(Patt,Record)>0
Returns
ID Record
1 IA12345
2 IA33333
3 IA33333
4 IA44444
5 MO12345
EDIT
I should add that runs of 3 is too small, it is a small matter tweak the sub-queries so 333 becomes 3333 and 123 becomes 1234

How do you find a missing number in a table field starting from a parameter and incrementing sequentially?

Let's say I have an sql server table:
NumberTaken CompanyName
2 Fred 3 Fred 4 Fred 6 Fred 7 Fred 8 Fred 11 Fred
I need an efficient way to pass in a parameter [StartingNumber] and to count from [StartingNumber] sequentially until I find a number that is missing.
For example notice that 1, 5, 9 and 10 are missing from the table.
If I supplied the parameter [StartingNumber] = 1, it would check to see if 1 exists, if it does it would check to see if 2 exists and so on and so forth so 1 would be returned here.
If [StartNumber] = 6 the function would return 9.
In c# pseudo code it would basically be:
int ctr = [StartingNumber]
while([SELECT NumberTaken FROM tblNumbers Where NumberTaken = ctr] != null)
ctr++;
return ctr;
The problem with that code is that is seems really inefficient if there are thousands of numbers in the table. Also, I can write it in c# code or in a stored procedure whichever is more efficient.
Thanks for the help
Fine, if this question isn't going to be closed, I may as well Copy and paste my answer from the other one:
I called my table Blank, and used the following:
declare #StartOffset int = 2
; With Missing as (
select #StartOffset as N where not exists(select * from Blank where ID = #StartOffset)
), Sequence as (
select #StartOffset as N from Blank where ID = #StartOffset
union all
select b.ID from Blank b inner join Sequence s on b.ID = s.N + 1
)
select COALESCE((select N from Missing),(select MAX(N)+1 from Sequence))
You basically have two cases - either your starting value is missing (so the Missing CTE will contain one row), or it's present, so you count forwards using a recursive CTE (Sequence), and take the max from that and add 1
Tables:
create table Blank (
ID int not null,
Name varchar(20) not null
)
insert into Blank(ID,Name)
select 2 ,'Fred' union all
select 3 ,'Fred' union all
select 4 ,'Fred' union all
select 6 ,'Fred' union all
select 7 ,'Fred' union all
select 8 ,'Fred' union all
select 11 ,'Fred'
go
I would create a temp table containing all numbers from StartingNumber to EndNumber and LEFT JOIN to it to receive the list of rows not contained in the temp table.
If NumberTaken is indexed you could do it with a join on the same table:
select T.NumberTaken -1 as MISSING_NUMBER
from myTable T
left outer join myTable T1
on T.NumberTaken= T1.NumberTaken+1
where T1.NumberTaken is null and t.NumberTaken >= STARTING_NUMBER
order by T.NumberTaken
EDIT
Edited to get 1 too
1> select 1+ID as ID from #b as b
where not exists (select 1 from #b where ID = 1+b.ID)
2> go
ID
-----------
5
9
12
Take max(1+ID) and/or add your starting value to the where clause, depending on what you actually want.

mysql: duplicate certain rows using SQL?

I have a table that looks like this:
nid vid tid
1 2 3
2 2 4
3 2 4
4 2 3
I'd like to run some SQL that will take each one of those rows and create another based on it like so:
foreach row where vid=2, create a duplicate row where vid = 3
So I'll end up with this:
nid vid tid
1 2 3
2 2 4
3 2 4
4 2 3
1 3 3
2 3 4
3 3 4
4 3 3
The table is not that big (less than 500 rows, I think) and this is a one-time thing (so the code does not need to be amazingly optimized or anything). Thanks!
you’ll probably want this:
INSERT INTO `table`(`nid`, `vid`, `nid`)
SELECT `nid`, `vid`+1, `nid`
FROM `table`
WHERE `vid` = 2
it inserts all rows, with vid incremented by 1
If you want a general solution (i.e. all values of vid, but adding one to each of them), this is just adapting dandres' answer:
INSERT INTO TheTable(nid, vid_incremented, nid)
SELECT nid, vid + 1 as vid_incremented , nid
FROM TheTable
Edit: fixed to do arithmetic in select statement.
Could you do the following:
INSERT INTO TheTable(nid, vid, nid)
SELECT nid, 3, nid
FROM TheTable
WHERE vid = 2
Two columns appear to have the same name, but the above should work. It takes the set of Vid = 2 elements, inserts them again but using Vid = 3.
Create another table with 2 fixed records, e.g. TwoRec (vvid), with values 2 and 3
Do a cartesian join with TwoRec, i.e.
SELECT TheTable.nid, TwoRec.vvid, TheTable.nid
FROM TheTable, TwoRec
WHERE TheTable.vid = 2;
I'd create a temp table of all of the vids you want to use:
create temporary table Vids
(
vid int
)
declare #vid int
declare #maxvid int
set #vid = 1
set #maxvid = 500
while #vid < #maxvid
begin
insert into vids values(#vid)
set #vid = #vid + 1
end
Then, I'd use that temp table to build out your other table:
select
t2.id,
t1.vid,
t2.nid
into newtable
from
vids t1
cross join tbl t2
order by
t1.vid,
t2.id