Please let me know if there is any query where in I remove the repeating entries in a row.
For eg: I have a table which has name with 9 telephone numbers:
Name Tel0 Tel1 Tel2 Tel3 Tel4 Tel5 Tel6 Tel7 Tel8
John 1 2 2 2 3 3 4 5 1
The final result should be as shown below:
Name Tel0 Tel1 Tel2 Tel3 Tel4 Tel5 Tel6 Tel7 Tel8
John 1 2 3 4 5
regards
Maddy
I fear that it will be more complicated to keep this format than to split the table in two as I suggested. If you insist on keeping the current schema then I would suggest that you query the row, organise the fields in application code and then perform an update on the database.
You could also try to use SQL UNION operator to give you a list of the numbers, a UNION by default will remove all duplicate rows:
SELECT Name, Tel FROM
(SELECT Name, Tel0 AS Tel FROM Person UNION
SELECT Name, Tel1 FROM Person UNION
SELECT Name, Tel2 FROM Person) ORDER BY Name ;
Which should give you a result set like this:
John|1
John|2
You will then have to step through the result set and saving each number into a separate variable (skipping those variables that do not exist) until the "Name" field changes.
Tel1 := Null; Tel2 := Null;
Name := ResultSet['Name'];
Tel0 := ResultSet['Tel'];
ResultSet.Next();
if (Name == ResultSet['Name']) {
Tel1 := ResultSet['Tel'];
} else {
UPDATE here.
StartAgain;
}
ResultSet.Next();
if (Name == ResultSet['Name']) {
Tel2 := ResultSet['Tel'];
} else {
UPDATE here.
StartAgain;
}
I am not recommending you do this, it is very bad use of a relational database but once implemented in a real language and debugged that should work.
Related
I have a column (text) in my Postgres DB (v.10) with a JSON format.
As far as i now it's has an array format.
Here is an fiddle example: Fiddle
If table1 = persons and change_type = create then i only want to return the name and firstname concatenated as one field and clear the rest of the text.
Output should be like this:
id table1 did execution_date change_type attr context_data
1 Persons 1 2021-01-01 Create Name [["+","name","Leon Bill"]]
1 Persons 2 2021-01-01 Update Firt_name [["+","cur_nr","12345"],["+","art_cd","1"],["+","name","Leon"],["+","versand_art",null],["+","email",null],["+","firstname","Bill"],["+","code_cd",null]]
1 Users 3 2021-01-01 Create Street [["+","cur_nr","12345"],["+","art_cd","1"],["+","name","Leon"],["+","versand_art",null],["+","email",null],["+","firstname","Bill"],["+","code_cd",null]]
Disassemble json array into SETOF using json_array_elements function, then assemble it back into structure you want.
select m.*
, case
when m.table1 = 'Persons' and m.change_type = 'Create'
then (
select '[["+","name",' || to_json(string_agg(a.value->>2,' ' order by a.value->>1 desc))::text || ']]'
from json_array_elements(m.context_data::json) a
where a.value->>1 in ('name','firstname')
)
else m.context_data
end as context_data
from mutations m
modified fiddle
(Note:
utilization of alphabetical ordering of names of required fields is little bit dirty, explicit order by case could improve readability
resulting json is assembled from string literals as much as possible since you didn't specified if "+" should be taken from any of original array elements
the to_json()::text is just for safety against injection
)
I have a legacy data logging industrial app that I'm writing a new interface for. The program lets you select points on devices, save those to a profile, then select devices to apply that profile for. When you apply the profile it create a table for each device using the devices unique ID as the table name and creates columns for each point of data you will be logging using the unique point ID. For example I select 3 points of information to datalog and it saves those three as a Profile (into it's own table) and then the point into the Points table tagged with that Profile:
PointID PointName ProfileID
33 Temp23 1
34 Hum14 1
35 Stat 1
I then select a couple devices and apply that profile which saves to the Device table:
DeviceID DeviceName ProfileID
5 NWUnit 1
6 NEUnit 1
After it saves the devices it creates the table per device such as:
Table Name: DEV5
Column 1: PNT1 - Float
Column 2: PNT2 - Float
Column 3: PNT3 - Bit
As you can see the table names are directly related to the device ID and the column names directly related to the point ID. I can add/remove points form the profile, it adds/deletes columns as needed. Apply a different profile and the DEV tables get deleted and recreated. Everything works as expected like the old program that's being replaced.
Now I need to actually do the data logging. I created a simple view:
SELECT dbo.Devices.DeviceID, dbo.Points.PointName, dbo.Points.PointID
FROM dbo.Devices LEFT OUTER JOIN
dbo.Points ON dbo.Devices.ProfileID = dbo.Points.ProfileID
Again so far so good:
DeviceID PointName PointID
5 Temp23 33
5 Hum14 34
5 Stat 35
6 Temp23 33
6 Hum14 34
6 Stat 35
I take this and I throw it in a DataTable, do a Columns.Add("Value") to it to get a blank column, then go through a data retrieval. When it's done I now have the table with the retrieved value:
DeviceID PointName PointID Value
5 Temp23 33 72.34
5 Hum14 34 43.8
5 Stat 35 1
6 Temp23 33 76.80
6 Hum14 34 54.2
6 Stat 35 0
And that's where I'm stuck. I need to take this info, use the DeviceID for the table name and the PointID for the column name, and insert the data. In otherwords I need this:
Dim myParamList As New Dictionary(Of String, Object) From {
{"#SampleTime", Date.Now},
{"#DevTable", "Dev" & r.Item("DeviceID")},
HOW DO I CYCLE THROUGH TO GET THE COLUMNS HERE?
}
UpdateDatabase(MySQLConnection, "INSERT INTO #DevTable (SampleTime, AND HERE?) VALUES (#SampleTime, AND HERE)", myParamList)
I cannot figure out the cycling through part. I thought I should use a Count + Group By to find out how many rows have the same device ID, like DeviceID 5 has 3 rows, and use that to cycle through that number of times but I'm just stuck trying to figure out how.
Any suggestions on the best way to do this?
So after struggling with trying to do a GroupBy on a dataview I decided to just do another database query with a Count(*) and GroupBy DeviceID to grab my unique DeviceIDs:
DeviceID RowCount
5 3
6 3
I then used that to loop through the device ID's and used the ID to filter myView as needed. Then I dynamically created a parameterized SQL string and update the database:
For Each r As DataRow In DevIDDataset.Tables("DeviceIDs").Rows
myView.RowFilter = "DeviceID=" & r.Item("DeviceID")
Dim myParamList As New Dictionary(Of String, Object) From {
{"#SampleTime", Date.Now}
}
Dim myFields As String = "SampleTime"
Dim myValues As String = "#SampleTime"
For Each row As DataRowView In myView
Dim myPointID As String = row.Item("PointID")
myFields += ",obj" & myPointID
myParamList.Add("#obj" & myPointID, row.Item("RetrievedValue"))
myValues += ",#obj" & myPointID
Next
UpdateDatabase(MySQLConnection, "INSERT INTO dev" & r.Item("DeviceID") & " (" & myFields & ") VALUES (" & myValues & ")", myParamList)
Next
Not pretty but it does what it needs to do and I can't think of any other way to do it.
I have a string of email addresses. For example, "a#a.com; b#a.com; c#a.com"
My database is:
record | flag1 | flag2 | emailaddresss
--------------------------------------------------------
1 | 0 | 0 | a#a.com
2 | 0 | 0 | b#a.com
3 | 0 | 0 | c#a.com
What I need to do is parse the string, and if the address is not in the database, add it.
Then, return a string of just the record numbers that correspond to the email addresses.
So, if the call is made with "A#a.com; c#a.com; d#a.com", the rountine would add "d#a.com", then return "1, 3,4" corresponding to the records that match the email addresses.
What I am doing now is calling the database once per email address to look it up and confirm it exists (adding if it doesn't exist), then looping thru them again to get the addresses 1 by 1 from my powershell app to collect the record numbers.
There has to be a way to just pass all of the addresses to SQL at the same time, right?
I have it working in powershell.. but slowly..
I'd love a response from SQL as shown above of just the record number for each email address in a single response. That is, "1,2,4" etc.
My powershell code is:
$EmailList2 = $EmailList.split(";")
# lets get the ID # for each eamil address.
foreach($x in $EmailList2)
{
$data = exec-query "select Record from emailaddresses where emailAddress = #email" -parameter #{email=$x.trim()} -conn $connection
if ($($data.Tables.record) -gt 0)
{
$ResponseNumbers = $ResponseNumbers + "$($data.Tables.record), "
}
}
$ResponseNumbers = $($ResponseNumbers+"XX").replace(", XX","")
return $ResponseNumbers
You'd have to do this in 2 steps. Firstly INSERT the new values and then use a SELECT to get the values back. This answer uses delimitedsplit8k (not delimitedsplit8k_LEAD) as you're still using SQL Server 2008. On the note of 2008 I strongly suggest looking at upgrade paths soon as you have about 6 weeks of support left.
You can use the function to split the values and then INSERT/SELECT appropriately:
DECLARE #Emails varchar(8000) = 'a#a.com;b#a.com;c#a.com';
WITH Emails AS(
SELECT DS.Item AS Email
FROM dbo.DelimitedSplit8K(#Emails,';') DS)
INSERT INTO YT (emailaddress) --I don't know what the other columns value should be, so have excluded
SELECT E.Email
FROM dbo.YourTable YT
LEFT JOIN Emails E ON YT.emailaddress = E.Email
WHERE E.Email IS NULL;
SELECT YT.record
FROM dbo.YourTable YT
JOIN dbo.DelimitedSplit8K(#Emails,';') DS ON DS.Item = YT.emailaddress;
I have SSIS package, which retrieves all records including duplicates. My question is how to add an incremental value for the duplicate records (only the ID and PropertyID).
Eg
Records from a Merge Join
ID Name PropertyID Value
1 A 1 123
1 A 1 223
2 B 2 334
3 C 1 22
3 C 1 45
Now I need to append an incremental value at the end of the each record as
ID Name PropertyID Value RID
1 A 1 123 1
1 A 1 223 2
2 B 2 334 1
3 C 1 22 1
3 C 1 45 2
Since ID 1 & 3 are returned twice, the first record has RID as 1 and the second record as 2.
ID and PropertyID need to be considered to generate the Repeating ID i.e RID.
How can I do it in SSIS or using SQL command?
Update #1:
Please correct me if I'm wrong, since the data is not stored in any table yet, I'm unable to use the select query using rownumber(). Any way I can do it from the Merge Join?
You could use ROW_NUMBER:
SELECT ID,
Name,
PropertyID,
Value,
ROW_NUMBER() OVER(PARTITION BY ID, PropertyID ORDER BY Value) As RID
FROM TableName
This will do the job for you: https://paultebraak.wordpress.com/2013/02/25/rank-partitioning-in-etl-using-ssis/
You will need to write a custom script, something like this:
public
class
ScriptMain : UserComponent
{
string _sub_category = “”;
int _row_rank = 1;
public override void Input0_ProcessInputRow(Input0Buffer Row)
{
if (Row.subcategory != _sub_category)
{
_row_rank = 1;
Row.rowrank = _row_rank;
_sub_category = Row.subcategory;
}
else
{
_row_rank++;
Row.rowrank = _row_rank;
}
}
}
I'm struggling to find an approach to the following problem, can anyone suggest a high level approach.
Using talend, I have an input set of values for a set of accounts (from CSV):
AccountId, ValueXYZ__c
I want to store ValueXYZ against the SFDC account, which is no problem, but then I want to totalise ValueXYZ up for all the accounts with the same parent to
Account.Parent.TotalValueXYZ
I then want to "roll" this all the way up the accounts hierarchy:
Imagine account hierarchy:
A
-B
--C
--D
-E
--F
--G
I want 3 values on A:
ValueXYZ = account A's ValueXYZ
TotalValueXYZ = total of ValueXYZ values for all accounts under A in the hierarchy
TOTAL = formula field to add together the previous 2 values
I want 3 values on account B
ValueXYZ = account B's ValueXYZ
TotalValueXYZ = total of ValueXYZ values for accounts C & D
TOTAL = formula field to add together the previous 2 values
I want 3 values on account C
ValueXYZ = account C's ValueXYZ
TotalValueXYZ = 0
TOTAL = formula field to add together the previous 2 values
I've tried several approaches, but can't get any of them to work!
Where is the hierarchy information stored? If you can flatten the hierarchy information in a key-value pair format, then it is straightforward. Just read your input file and do a lookup/join on the hierarchy file. You will have to loop through until you get to the base record
The crux of my problem was in not knowing each accounts position in a hierarchy. Once I had that in place, I could loop from the lowest level to the highest level, totalling these values up to their parents.
Here is the T-SQL I wrote to mark each account with it's Hierarchy Position (HILEVEL)
TRUNCATE TABLE [TALEND_WORKSPACE].[dbo].[SFDCAccount]
INSERT INTO [TALEND_WORKSPACE].[dbo].[SFDCAccount] (Id, ParentId, QCIYTDOneTime, QCIYTDRecurring, HILEVEL)
SELECT Id, ParentId, ValueXYZ, '0'
FROM [TALEND_WORKSPACE].[dbo].[SFDCAccountRawData]
WHERE ParentId = ' ';
USE TALEND_WORKSPACE
IF OBJECT_ID('dbo.sfdcaccounthierarchy', 'P') IS NOT NULL
DROP PROCEDURE [dbo].[sfdcaccounthierarchy];
GO
CREATE PROCEDURE [dbo].[sfdcaccounthierarchy]
AS
DECLARE #v_counter int;
DECLARE #v_lastccounter int;
DECLARE #v_max int;
SET #v_counter = 0;
SET #v_lastccounter = 0;
SET #v_max = 10;
WHILE (#v_counter < #v_max)
BEGIN
SET #v_lastccounter = #v_counter;
SET #v_counter = #v_counter+1;
PRINT #v_counter;
INSERT INTO [dbo].[SFDCAccount] (Id, ParentId, QCIYTDOneTime, QCIYTDRecurring, HILEVEL)
SELECT Id, ParentId, ValueXYZ, #v_counter
FROM [TALEND_WORKSPACE].[dbo].[SFDCAccountRawData]
WHERE ParentId IN (SELECT Id FROM [TALEND_WORKSPACE].[dbo].[SFDCAccount]
WHERE HILEVEL = #v_lastccounter);
if ##ROWCOUNT != 0
BREAK;
END
GO
EXEC [TALEND_WORKSPACE].[dbo].[sfdcaccounthierarchy];