How to add alphabet increment? - c#

i have this table
series
id
1975
1
1985
1
1995
2
2000
2
what we trying to achieve is we add alphabet increment where id is same, example series will be 1975A, 1985B, and then 1995A 2000B when id is same, it is possible to do that? in query or in c# mvc code?

You can use below query.
At first,
I have added row number par group/ partition
Then as we know CHR(65)='A', Thus I have added 64 + auto row_rumber
And Convert to CHAR.
Add result with series field.
SELECT
CONCAT
(
series ,
CHR(64 + CAST ( row_number() OVER(PARTITION BY id order by id) AS integer ))
)
,id from table1

Related

SQL Server : check not existing number into a table

I have a Clients table already populated by thousands of records and now I need to search for a non-existing number in the card number column starting from the number x.
Example: I would like to search for the first available card number starting from number 2000.
Unfortunately I cannot select MAX() as there are records with 9999999 (which is the limit).
Is it possible to do this search through a single SELECT?
It's possible with a few nested SELECTs:
SELECT MIN(`card_number`) + 1 as next_available_number
FROM( SELECT (2000-1) as `card_number`
UNION
SELECT `card_number`
FROM clients
WHERE `card_number` >= 2000
) tmp
WHERE NOT EXISTS ( SELECT NULL
FROM clients
WHERE `card_number` = tmp.`card_number` + 1 )
It can be done with a self-join on your clients table, where you search for the lowest cardnumber for which the cardnumber + 1 does not exist.
In case x is 12, the query would be:
SELECT MIN(cardnumber) + 1
FROM clients
WHERE cardnumber + 1 NOT IN (SELECT cardnumber FROM clients)
AND cardnumber + 1 > 12
Eg. with a dataset of
INSERT INTO clients (cardnumber) VALUES
(1),(2),(3),(4),(5),(6),(7),(8),(9),(11),(12),(13),(14),(15),(17),(18)
this returns 16, but not 10.
Example on SQL Fiddle.
I think this is very similar to this question, but the minimum criteria is new.
If the credit card is represented as integer in your table and your starting number is 2000 you could do something like:
SELECT top 1 (card_id + 1)
FROM CreditCards t
WHERE card_id IN (
SELECT card_id
FROM CreditCards
WHERE card_id LIKE '%[2][0][0][0]%'
)
AND NOT EXISTS (SELECT 1 FROM CreditCards t2 WHERE t2.card_id = t.card_id + 1)
ORDER BY card_id
Example data (Table: CreditCards):
card_id
2000002
2000103
2000000
2000108
2000106
3000201
1000101
Result is: 2000001
Note that %[2][0][0][0]% is fixed here. You could also introduce a parameter.
It is not an optimal solution, but it does the trick.

TSQL Transpose a column of a table into a row

I have a temporary table with one column containing 3 pieces of data: Code, Date, and Quantity.
Example:
-------
FR123456
24/02/1988
500
I need to extract the data in this column into separate columns.
Example:
Code | Date | Quantity
--------- ----------- ----
FR123456 | 24/02/1988 | 500
I used this code:
SELECT [1], [2], [3]
FROM
(
SELECT row_number() OVER (ORDER BY splitdata DESC) AS Id, splitdata
FROM splitdata
) AS SourceTable
PIVOT
(
MIN (splitdata)
FOR id IN ([1], [2], [3])
) AS PivotTable;
The problem with it is that once the content of data changes, I may get the quantity content into the date column due to the aggregate function (MIN).
I assume this is SQL-Server related...
Your problem is: A SQL-Server table does not have any kind of implicit sort order. A simple SELECT * FROM SomeWhere can return in the sort order you've inserted your data, but can return completely different as well. The only chance to ensure a sort order is an ORDER BY at the outer-most query against a (set of) unique column(s).
You can create a sort order by kind of analysing your data:
This is a mockup-table with your test data:
DECLARE #mockup TABLE(YourColumn VARCHAR(100));
INSERT INTO #mockup VALUES
('FR123456')
,('24/02/1988')
,('500');
--The query will check the values if they can be casted to a number, to a date or not.
--This will be used to place a sort order to the values.
--I use 105 in CONVERT to enforce the dateformat dd-MM-yyyy
SELECT CASE WHEN TRY_CONVERT(DATE,YourColumn,105) IS NOT NULL THEN 2
ELSE CASE WHEN TRY_CAST(YourColumn AS INT) IS NOT NULL THEN 3 ELSE 1
END
END AS SortOrder
,YourColumn
FROM #mockup
ORDER BY SortOrder;
But if there are several triplets in your table, not just one as in your sample, I'm afraid you're lost...
Btw: Your own approach tries to do exactly the same:
SELECT row_number() OVER (order by splitdata desc)as Id
This will create kind of a sort order number, but it will be random (a quantity will appeare before or after the date depending on alphanumerical rules).
Hint
Add an IDENTITY column to your table. This will use an increasing number for any row the moment it is created. These values can be used to enforce the order as inserted (by using ORDER BY with this column).
UPDATE: Your query
SELECT [1], [2] , [3]
FROM
(SELECT CASE WHEN TRY_CONVERT(DATE,splitdata,105) IS NOT NULL THEN 2
ELSE CASE WHEN TRY_CAST(splitdata AS INT) IS NOT NULL THEN 3 ELSE 1
END
END AS Id , splitdata
from #mockup ) AS SourceTable
PIVOT
(
MIN (splitdata)
FOR id IN ([1], [2], [3])
) AS PivotTable;

Faster way to insert records into database

So I currently have a database table of about 70,000 names. What I want to do is take 3000 random records from that database and insert them into another table where each name has a row for all the other names. In other words, the new table should look like this:
John, jerry
john, alex
john, sam
jerry, alex
jerry, sam
alex, sam
This means that I should be adding summation n rows to the table. My current strategy is to use two nested for loops to add these rows one at a time and then removing the first name from the list of names to add in order to ensure I dont have a duplicate record with different ordering.
My question is this: is there a faster way to do this, perhaps through parallel for loops or PLINQ or some other option that I a have not mentioned?
Given a table "Names" with an nvarchar(50) column "Name" with this data:
Adam
Bob
Charlie
Den
Eric
Fred
This query:
-- Work out the fraction we need
DECLARE #frac AS float;
SELECT #frac = CAST(35000 AS float) / 70000;
-- Get roughly that sample size
WITH ts AS (
SELECT Name FROM Names
WHERE #frac >= CAST(CHECKSUM(NEWID(), Name) & 0x7FFFFFFF AS float) / CAST (0X7FFFFFFF AS int)
)
-- Match each entry in the sample with all the other entries
SELECT x.Name + ', ' + y.Name
FROM ts AS X
CROSS JOIN
Names AS Y
WHERE x.Name <> y.Name
produces results of the form
Adam, Bob
Adam, Charlie
Adam, Den
Adam, Eric
Adam, Fred
Charlie, Adam
Charlie, Bob
Charlie, Den
Charlie, Eric
Charlie, Fred
Den, Adam
Den, Bob
Den, Charlie
Den, Eric
Den, Fred
The results will vary by run; a sample of 3000 out of 70000 will have approximately 3000 * 70000 result rows. I used 35000./70000 because the sample size I used was only 6.
If you want only the names from the sample used, change CROSS JOIN Names AS Y to CROSS JOIN ts AS Y, and there will then be approximately 3000 * 3000 result rows.
Reference: The random sample method was taken from the section "Important" in Limiting Result Sets by Using TABLESAMPLE.
You will need to figure out the random part
select t1.name, t2.name
from table t1
join table t2
on t1.name < t2.name
order by t1.name, t2.name
You need to materialize the newid
declare #t table (name varchar(10) primary key);
insert into #t (name) values
('Adam')
, ('Bob')
, ('Charlie')
, ('Den')
, ('Eric')
, ('Fred');
declare #top table (name varchar(10) primary key);
insert into #top (name)
select top (4) name from #t order by NEWID();
select * from #top;
select a.name, b.name
from #top a
join #top b
on a.name < b.name
order by a.name, b.name;
Using a Number table to simulate names.
single query, using a triangular join
WITH all_names
AS (SELECT n,
'NAME_' + Cast(n AS VARCHAR(20)) NAME
FROM number
WHERE n < 70000),
rand_names
AS (SELECT TOP 3000 *
FROM all_names
ORDER BY Newid()),
ordered_names
AS (SELECT Row_number()
OVER (
ORDER BY NAME) rw_num,
NAME
FROM rand_names)
SELECT n1.NAME,
n2.NAME
FROM ordered_names n1
INNER JOIN ordered_names n2
ON n2.rw_num > n1.rw_num

Sequential Increment in Alphanumeric Invoice Number using MSSQL

i have a table named as sales. In this table i have a column Invoice_Number. What i want to achieve is to get invoice number in alphanumeric sequential order i.e. one Static Letter and then a number that changes just like A1,A2,A3... and so on. i don't want to change A to B as i saw in rest of the examples.
I can get the numeric increment by this query:
Select IsNull(MAX([Invoice_Number] + 1), 1) from sales
But it cannot add an alphabet prior to it.
Thanks.
Try using a cast like so to return a varchar, let me know if this helps :).
SELECT 'A' + CAST(ISNULL(MAX([Invoice_Number] + 1), 1) AS nvarchar) FROM sales
You could use your existing identity column as a seed. Combine this with a computed column to return the InvoiceNumber.
-- Combine a seed with a computed column.
CREATE TABLE #Example
(
Seed INT IDENTITY(1,1),
InvoiceNumber AS 'A' + CAST(Seed AS VARCHAR(5)),
Customer VARCHAR(25)
);
-- Add some sample records.
INSERT INTO #Example
(
Customer
)
VALUES
('A PLC'),
('B PLC'),
('C LTD')
;
-- Returns InvoiceNumbers A1, A2 & A3.
SELECT
*
FROM
#Example
;

What is a good approach in MS SQL Server 2008 to join on a "best" match?

In essence I want to pick the best match of a prefix from the "Rate" table based on the TelephoneNumber field in the "Call" table. Given the example data below, '0123456789' would best match the prefix '012' whilst '0100000000' would best match the prefix '01'.
I've included some DML with some more examples of correct matches in the SQL comments.
There will be circa 70,000 rows in the rate table and the call table will have around 20 million rows. But there will be a restriction on the Select from the Call table based on a dateTime column so actually the query will only need to run over 0.5 million call rows.
The prefix in the Rate table can be up to 16 characters long.
I have no idea how to approach this in SQL, I'm currently thinking of writing a C# SQLCLR function to do it. Has anyone done anything similar? I'd appreciate any advice you have.
Example Data
Call table:
Id TelephoneNumber
1 0123456789
2 0100000000
3 0200000000
4 0780000000
5 0784000000
6 0987654321
Rate table:
Prefix Scale
1
01 1.1
012 1.2
02 2
078 3
0784 3.1
DML
create table Rate
(
Prefix nvarchar(16) not null,
Scale float not null
)
create table [Call]
(
Id bigint not null,
TelephoneNumber nvarchar(16) not null
)
insert into Rate (Prefix, Scale) values ('', 1)
insert into Rate (Prefix, Scale) values ('01', 1.1)
insert into Rate (Prefix, Scale) values ('012', 1.2)
insert into Rate (Prefix, Scale) values ('02', 2)
insert into Rate (Prefix, Scale) values ('078', 3)
insert into Rate (Prefix, Scale) values ('0784', 3.1)
insert into [Call] (Id, TelephoneNumber) values (1, '0123456789') --match 1.2
insert into [Call] (Id, TelephoneNumber) values (2, '0100000000') --match 1.1
insert into [Call] (Id, TelephoneNumber) values (3, '0200000000') --match 2
insert into [Call] (Id, TelephoneNumber) values (4, '0780000000') --match 3
insert into [Call] (Id, TelephoneNumber) values (5, '0784000000') --match 3.1
insert into [Call] (Id, TelephoneNumber) values (6, '0987654321') --match 1
Note: The last one '0987654321' matches the blank string because there are no better matches.
Since this is based on partial matching, a subselect would be the only viable option (unless, like LukeH assumes, every call is unique)
select
c.Id,
c.TelephoneNumber,
(select top 1
Scale
from Rate r
where c.TelephoneNumber like r.Prefix + '%' order by Scale desc
) as Scale
from Call c
SELECT t.Id, t.TelephoneNumber, t.Prefix, t.Scale
FROM
(
SELECT *, ROW_NUMBER() OVER
(
PARTITION BY c.TelephoneNumber
ORDER BY r.Scale DESC
) AS RowNumber
FROM [call] AS c
INNER JOIN [rate] AS r
ON c.TelephoneNumber LIKE r.Prefix + '%'
) AS t
WHERE t.RowNumber = 1
ORDER BY t.Id
Try this one:
select Prefix, min(c.TelephoneNumber)
from Rate r
left outer join Call c on c.TelephoneNumber like left(Prefix + '0000000000', 10)
or c.TelephoneNumber like Prefix + '%'
group by Prefix
You can use a left join to try to find a "better" match, and then eliminate such matches in your where clause. e.g.:
select
*
from
Call c
inner join
Rate r
on
r.Prefix = SUBSTRING(c.TelephoneNumber,1,LEN(r.Prefix))
left join
Rate r_anti
on
r_anti.Prefix = SUBSTRING(c.TelephoneNumber,1,LEN(r_anti.Prefix)) and
LEN(r_anti.Prefix) > LEN(r.Prefix)
where
r_anti.Prefix is null

Categories