How to change STRING Id to a new INT Id? - sql

I would like to use an extension in PostgreSQL, which does not work with STRING or CHAR Ids. I have already a .sql-Script to create all the tables and all .backups for these tables, which have some columns with string ids.
The idea is to load the tables with the values and then to add a new column with Unique INT Ids for every String id. There are some same values of string ids in some tuples, that's why I can't create a new serial int.
How is it possible to solve this problem?
Thank you!

Assume your data is as follows:
Stringid || data
1 || as
1 || aslh
1 || akk
2 || abb
2 || as
Your query have to be :
Select Stringid, data,
Row_number()over(partition by
Stringid order by Stringid as) as id
from tab1;
Output:
Stringid || data || id
1 || as || 1
1 || aslh || 2
1 || akk || 3
2 || abb || 1
2 || as || 2

Related

Splitting up Group By for similar values in a column within SQL Server

I am trying to split up the values in column5 so that when using a GROUP BY on column5 (seen below) the 2 value isn't all grouped together. Instead, the values will be separated out so that the first value of 2 is in it's own group the the second group is the value 46675 and the final third groupings will be the last couple 2 values. In short, I am looking for a way to split up the 2 value so that it does not aggregate all the 2 values together, but instead splits them into separate groupings (mirroring the 'Groups' column). The intended outcome is to have the each separated 2 values be aggregated together in their own respective groups. Added tidy table and picture from Excel file.
||Column1||Column2||Column3||Column4||Column5||Groups||
|| 1 || NO || A || F || 2 || 1 ||
|| 2 || Yes || B || C || 46 || 2 ||
|| 3 || NO || C || F || 2 || 3 ||
|| 4 || NO || D || F || 2 || 3 ||
Image of Table from Excel File
This is the prototype gaps and islands problem. You're looking for runs in Column5 ordered by Column1:
with data as (
select *,
row_number() over (order by Column1) -
row_number() over (partition by Column5 order by Column1) as grp
)
select * from data order by Column1;

Select Rows having values matching in 2 other columns

Table
Id || IdFrom || IdTo
--------------------------
1 || null || 2
2 || 1 || null
3 || null || 5
4 || null || 6
5 || 3 || 9
6 || 4 || 7
7 || 6 || null
8 || null || null
9 || 5 || 10
10 || 9 || null
947 || null || 949
949 || 947 || 952
950 || null || 951
951 || 950 || 952
952 || 951 || null
Need to get all rows or just specifically the Ids that are found between all 3 columns when specifying a given Id. So a SELECT (all ids found in the IdFrom or IdTo and Those IdFrom's or IdTo's are in other IdFrom's or IdTo's)
Results when searching for Id 1 would give results of Ids 1 and 2
Results when searching for Id 2 would give results of Ids 1 and 2
Results when searching for Id 3,5,9, or 10 would give results of Ids 3,5,9, and 10
Results when searching for Id 4,6, or 7 would give results of Ids 4,6,and 7
My current search is an iteration getting IdFrom and IdTo for Id, putting those found Id's into a tmp table and iterating back again searching for matches until no more distinct Ids are found. It works but is extremely ugly and takes longer then probably could...
Came across a query that can get all rows that have matching but not specifying for a particular id
DECLARE #SearchForId int = 1
SELECT
t1.ID,t1.IdFROM,t1.IdTO
FROM SomeTable t1
WHERE
(
EXISTS(SELECT Id FROM SomeTable tblFROM WHERE tblFROM.IdFROM = t1.Id) OR
EXISTS(SELECT Id FROM SomeTable tblTO WHERE IdTO.IDTRANSFEREDTO = t1.Id)
)
AND Id = 1 <<-- this part just gives that id obvious but without it, it gets everything in the entire table
EDIT: added new ids (947-952). The previous selected solution did provide ids 947 and 949 but missing 950,951,952. Tried adding another couple cte's like the previous solution to give all ids 947,949,950,951,952 but only giving 947 and 949. How to get all 5. That solution was much quicker by almost by 25x. Would like to keep it and get remainder id's
You need to do it using two recursive common table expressions.
declare #id int
set #id = 2
;WITH CTE1
AS(
SELECT c.*
FROM tbl c
WHERE c.Id = #id
UNION ALL
SELECT p.*
FROM CTE1 cte1_alias
INNER JOIN tbl p
ON p.IdFrom = cte1_alias.Id
),
CTE2
AS(
SELECT c.*
FROM tbl c
WHERE c.Id = #id
UNION ALL
SELECT p.*
FROM CTE2 cte2_alias
INNER JOIN tbl p
ON p.IdTo = cte2_alias.Id
)
SELECT Id FROM CTE1
Union
SELECT Id FROM CTE2
As I understand ORing the columns to be equal to the given value would be enough:
Declare #prm int = 1
Select Id
From SomeTable
Where Id=#prm Or IdFrom=#prm Or IdTo=#prm
or, for a different flavour, using in among columns
Declare #prm int = 1
Select Id
From SomeTable
Where #prm in (Id, IdFrom, IdTo)

SQL query group by and select the maximum absolute value

"Table1" structure is as shown below:
source table table1
Player_NAME || Player_NUMBER || Client_name || Client_country || Player_country|| Rating
GERALD || A1234 || BENFIELD || IND || IND || 76
GERALD ||A6578 || ROTFIELD || USA || USA || 64
KUMAR || P1234 || LFV || ARG || ARG || -24
KUMAR || P5678 ||JEURASIN || ARG || TUR ||-32
KUMAR || P0101 ||ARGENIA ||ARG ||POL ||-16
ANDREW ||R1234 || GENMAD || GER || GER || 23
I need to select the records from above table “Table1” and copy them to “Table2”.
I need to select the player record from table1 which satisfy the below conditions :
If a player has multiple client_names or multiple client_country, then select the record which has the maximum value of rating . If it is negavie, then take the absolute value of that value. i.e if the rating is -10 and -34, then take the absolute value which is greatest. i. e by taking absolute value it is 10,34 and 34 is greatest one.
For ex: Kumar has 3 diff client names or 3 diff client_country ,so for kumar the record with rating 32 should be selected ,after taking the absolute value of it.
Below is the expected output:
Player_NAME || Player_NUMBER ||Client_name || Client_country ||Player_country|| Rating
GERALD || A1234 || BENFIELD|| IND|| IND|| 76
KUMAR || P5678 || JEURASIN ||ARG ||TUR || -32
ANDREW || R1234 || GENMAD ||GER ||GER || 23
destination table-'table2'
You can try something like this:
INSERT INTO Table2
(
Player_Name,
Player_Number,
Cliet_Name,
Client_country,
Player_country,
Rating
)
SELECT
Player_Name,
Player_Number,
Cliet_Name,
Client_country,
Player_country,
MAX(ABS(Rating)) OVER (PARTITION BY player_Name ORDER BY Cliet_Name,
Client_country) as Rating
FROM
table1
If your DBMS supports Analytical Function you can utilize ROW_NUMBER:
select ... -- all columns but rn
from
(
select ... -- all columns
,row_number()
over (partition by player_name
order by abs(Rating) desc as rn
from table1
) as dt
where rn = 1;
Otherwise use a Correlated Subquery:
select *
from table1 as t1
where abs(rating) =
( select max(abs(rating))
from table1 as t2
where t1.player_name = t2.player_name
)
If you got multiple rows with the same max(abs(rating)) #1. will select one of them randomly, but #2 will select all.
I guess, this query will work:
select
max(abs(Rating))
from Table1
group by Player_NAME
To insert data into Table2, you can do it like so:
INSERT INTO Table2 (
Player_Name,
Player_Number,
Cliet_Name,
Client_country,
Player_country,
Rating
)
SELECT
t1.Player_Name,
t1.Player_Number,
t1.Cliet_Name,
t1.Client_country,
t1.Player_country,
t1.Rating
FROM Table1 t1
INNER JOIN (
SELECT
Player_NAME,
MAX(ABS(Rating)) as Rating
FROM Table1
GROUP BY Player_NAME
) t2 ON t2.Player_NAME = t1.Player_NAME AND ABS(t1.Rating) = t2.Rating

Oracle-sql : Query with hiererchical group by

I have a table like:
ID || Ent NAME || FUNCTION
1 || Dupuis || Signatory
1 || Daturt || Decision Maker
1 || Nobel || (Null )
2 || Karl || Decision Maker
2 || Titi || (Null )
3 || Cloves || (Null )
3 || Cardigan || (Null )
I want to get the most "important" people in a pre -established hierarchy (Signatory > Decision Maker > (Null ) )
So the expected result is:
ID Ent || NAME || FUNCTION
1 || Dupuis || Signatory
2 || Karl || Decision Maker
3 || Cardigan || (Null )
for the 3rd , i don't care of person selected .
I work in Oracle with extremely limited right , I can do that SELECT ( and this it is s*** ).
I have a solution bypass but it is extremely ugly and I am not satisfied:
(SELECT "ID Ent" max (NOM), max (FUNCTION)
FROM table
WHERE FUNCTION = 'Signatory' GROUP BY "ID Ent")
UNION
(SELECT "ID Ent" max (NOM), max (FUNCTION)
FROM table
WHERE FUNCTION = 'Decision Maker'
AND "ID Ent" not in (SELECT "ID Ent" FROM table WHERE FUNCTION = 'Signatory')
GROUP BY "ID Ent")
UNION
(SELECT "ID Ent" max (NOM), max (FUNCTION)
FROM table
WHERE FUNCTION = 'Decision Maker'
AND "ID Ent" not in (SELECT "ID Ent" in FUNCTION FROM table WHERE ('Signatory', 'Decision Maker'))
GROUP BY "ID Ent");
Do you have a better way to do this?
I would approach this using analytic functions:
select t.Id, t.Name, t.Function
from (select t.*,
row_number() over (partition by id
order by (case when function = 'Signatory' then 1
when function = 'Decision Maker' then 2
else 3
end)
) as seqnum
from table t
) t
where seqnum = 1;

Convert row data to new columns based on common ID value

I have an MS Access database for product ID list for each client ID.
Currently, the table is set up as the following:
CLI_ID || PRODUCT_ID
963506 || 49001608
968286 || 49001645
987218 || 00048038
987218 || 49001401
999999 || 9999999
999999 || 9999998
999999 || 9999997
999999 || 9999996
I would like to transpose the data to look like this:
CLI_ID || PRODUC1 || PRODUC2 || PRODUC3 || PRODUC4 ||
963506 || 49001608 ||
968286 || 49001645 ||
987218 || 00048038 || 49001401 ||
999999 || 99999999 || 99999998 || 99999997 || 99999996 ||
There are clients with more products than 4 in the example shown above so I would like the query to be expandable by counting # of product IDs in each client ID.
I took the code from ChrisPadgham's post and modified it to meet my needs...Here is what I have so far but it is not going further than PRODUC1:
TRANSFORM Last([PRODUCT_ID]) AS Details
SELECT Source_Table.CLI_ID
FROM Source_Table
GROUP BY Source_Table.CLI_ID
PIVOT "PRODUC" & (DCount("[PRODUCT_ID]","[Source_Table]", "[PRODUCT_ID]<>" &
[PRODUCT_ID] & " AND [CLI_ID]=" & [CLI_ID]) +1);
Any help would be appreciated!
Try adding a per client item counter to your data. Examples Found Here
It looks like your going to need to create a temp table as Access can't keep track of internal pointers when nesting the queries.
Create a temp table:
SELECT t1.CLI_ID, t1.PRODUCT_ID, (SELECT COUNT(*)
FROM Source_Table t2
WHERE t2.CLI_ID = t1.CLI_ID
AND t2.PRODUCT_ID <= t1.PRODUCT_ID
) AS PROD_COUNT INTO TEMP_CLI_PROD
FROM Source_Table AS t1
GROUP BY t1.CLI_ID, t1.PRODUCT_ID;
Then have your pivot table reference the temp table.
TRANSFORM Last(TEMP_CLI_PROD.PRODUCT_ID) AS LastOfPRODUCT_ID
SELECT TEMP_CLI_PROD.CLI_ID
FROM TEMP_CLI_PROD
GROUP BY TEMP_CLI_PROD.CLI_ID
PIVOT "PRODUCT " & TEMP_CLI_PROD.PROD_COUNT;
Output:
CLI_ID PRODUCT 1 PRODUCT 2 PRODUCT 3 PRODUCT 4
963506 49001608
968286 49001645
987218 00048038 49001401
999999 9999996 9999997 9999998 9999999
Jeff's answer is essentially correct in its approach, although a temporary table is not strictly required:
TRANSFORM First(PRODUCT_ID) AS whatever
SELECT CLI_ID
FROM
(
SELECT t1.CLI_ID, t1.PRODUCT_ID, 'PRODUCT_' & COUNT(*) AS XtabColumn
FROM
Source_Table AS t1
INNER JOIN
Source_Table AS t2
ON t1.CLI_ID = t2.CLI_ID
AND t1.PRODUCT_ID >= t2.PRODUCT_ID
GROUP BY t1.CLI_ID, t1.PRODUCT_ID
)
GROUP BY CLI_ID
PIVOT XtabColumn
returns
CLI_ID PRODUCT_1 PRODUCT_2 PRODUCT_3 PRODUCT_4
------ --------- --------- --------- ---------
963506 49001608
968286 49001645
987218 00048038 49001401
999999 9999996 9999997 9999998 9999999