Update table query with multiple values to a column - sql-server-2014

Table name: sales
Country salesAmount ID
USA 2345 1
USA 4356 2
USA 8762 3
USA 7809 4
USA 54324 5
UK 56790 6
UK 234145 NULL --> add 7
UK 567790 NULL --> add 8
UK 345678 NULL --> add 9
UK 343456 NULL --> add 10
UK 5467891 NULL --> add 11
UK 5923765 NULL --> add 12
Japan 43567890 NULL --> add 13
China 34566878 NULL --> add 14
France 343466 NULL --> add 15
Austria 3556689 NULL --> add 16
India 34567891 NULL --> add 17
Italy 3456767 NULL --> add 18
I need to fill in the null values with the numbers next to the arrows. Is there a quicker way to add those numbers into the ID column instead of using the code (Update sales set ID=7 where salesAmount = 234145)
I have to use the update statement for each row until the end which is time-consuming. Is there a stored procedure or function that I could use to update all the rows in one query? Please help. Thanks

Yes you can with ROW_NUMBER().
UPDATE A SET ID = New_ID FROM (
SELECT
ID,
ROW_NUMBER() OVER (ORDER BY CASE WHEN ID IS NULL THEN 1 ELSE 0 END, ID) AS New_ID
-- The row numbers are ordered by whether ID is null first, then by ID so that the nulls are at the end of the order
FROM sales
) AS A
WHERE ID IS NULL

Related

How to set value in all row if value is null , use value in Max

I have a table, Customers
My table is 'Customers' 4 columns
CusttomerId Name ContactName Country
1 Shere1 Ira USA
2 Shere2 Jenny Canada
3 Shere3 Fill Canada
4 Prod1 Joen China
Null Prod2 Clod Russia
Null Prod3 Brenda Finland
Null Prod4 Katy Belgium
in Column CusttomerId I need set value to all row is Null.
for example, after CusttomerId = 4 next value must be CusttomerId = 5 ,next row CusttomerId = 6 ...
Help me, please.
You could try using a mysql variable and assigning the initial value by a query for max()
set #id := (select max(CusttomerId) from Customers)
;
update Customers
set CusttomerId = (#id :=#id +1 )
where CusttomerId is null
;

Mysql DB table structure for the excel table having multiple sub columns under single colum

how to represent the below Excel table as a Mysql DB structure format where in a column has multiple sub columns as given below
Name Mon-Fri Sat Sun
Asia UK USA Asia UK USA Asia UK USA
Name1 0.25 0.25 0.5 0.5 - - - 0.5 -
Name2 0.5 0.5 1 1 - - - - -
Name3 0.25 0.25 0.5 0.5 - - - 0.5 -
You usually do this by adding a Time column to the data and "normalize" it:
Name Region Time Amount
------|-------|--------|-------
Name1 Asia Mon-Fri 0.25
Name1 Asia Sat 0.5
Name1 Asia Sun -
Name2 UK Mon-Fri 0.25
Name2 UK Sat -
...
See https://en.wikipedia.org/wiki/Database_normalization as well
For this first create a table of Days
tbl_days
id,
dayname
Then Create a group with these days. Group may be with one day or multiple days
tbl_group
id,
groupname,
days (make it comma separted with day id)
Then create a country master
tbl_countries
id,
country_name
Then assign the calculation like below
tbl_calculation
id,
group_id,
country_id,
value (nullable)
You can go with following Table Structure
tbl_Region -
ID , Name
1,UK
2,Asia
tbl_Date_allocation -
ID,WEEK_DAY_NAME
1, Mon
2 , Wed
3 ,...
tbl_types
Id, Name
1, Name 1
2, Name 2
......
tbl_allocation
id,region_id,date_allocation_id,type_id,value
1,1,2,1,0.25
id - auto increment
region_id,date_allocation_id,type_id - foreign keys to other table
What you have are two entities: something-that-has-a-name, let's call them People, and Geographic Area -- three of which are the values Asia, UK and USA. Then you have represented relationships between People and GAs. As seen from your data, a Person may relate to 0 or more GAs and a GA may relate to 0 or more people. Such a many to many relationship is maintained by an intersection or cross table (two names for the same thing). You further show two aspects of this relationship: a term ("Mon-Fri", "Sat" and "Sun") and an Amount.
The fact that Term values are days of the week are not really significant. There are three possible values so let's call them 1, 2 and 3. Amount looks like it could be any floating point value.
create table PersonGO(
PersonID int not null references People( ID ),
GAID int not null references Areas( ID ),
Term int not null check( Term in (1, 2, 3 )),
Amount float not null,
constraint PK_PersonGO primary key( PersonID, GRID )
);
The data stored in such table would look like this:
PersonID GAID Term Amount
1 1 1 0.25 -- Name1 Asia Mon-Fri
1 1 2 0.50 -- Name1 Asia Sat
1 2 1 0.25 -- Name1 UK Mon-Fri
1 2 3 0.50 -- Name1 UK Sun
1 3 1 0.50 -- Name1 USA Mon-Fri
2 1 1 0.50 -- Name2 Asia Mon-Fri
2 1 2 1.00 -- Name2 Asia Sat
2 2 1 0.50 -- Name2 UK Mon-Fri
2 3 1 1.00 -- Name2 USA Mon-Fri
3 1 1 0.25 -- Name3 Asia Mon-Fri
3 1 2 0.50 -- Name3 Asia Sat
3 2 1 0.25 -- Name3 UK Mon-Fri
3 2 3 0.50 -- Name3 UK Sun
3 3 1 0.50 -- Name3 USA Mon-Fri
Where there is no relationship for a particular person to a particular area on a particular term, such as Name1 with UK on Saturday, there is no entry. You would not have an entry with 0 or NULL in the Amount field. That would be unnecessary.
As your sample data looks like one week's worth of data and there would probably be one set of these entries for each week of a year, the table might have another field, WeekNum, with possible values such as 201601 for the first week of 2016, 201602 for the second week and so forth. You have a good deal of flexibility here. You could just as well merge this with the Term field: 2016011 for Mon-Fri of the first week, 2016012 for Sunday of the first week and so on. You could come up with something entirely different. Whatever makes the most sense to you.

Issue ordering columns by the first letter in blank columns

Here is my tables
|users|
|id| |lastname1| |lastname2| |name| |company_name|
1 Messi Ramirez Lionel
2 Gates Bush Bill
3 Klose Kazer Miroslav
4 Ozil Demon Mezut
5 Facebook
6 GMAIL
7 MYSPACE
8 Twitter
I'm trying to order company_name like a lastname1.
Some friends gave me this code but is not working with blank values just with NULL values:
select * from users
order by COALESCE(lastname1,company_name),lastname2,name ASC;
I should have this answer
Note: the first letter of "facebook" is F and "Gates" is G so it continues with the next letter.
5 Facebook
2 Gates Bush Bill
6 GMAIL
3 Klose Kazer Miroslav
1 Messi Ramirez Lionel
7 MYSPACE
4 Ozil Demon Mezut
8 Twitter
Please somebody can help me?
Use coalesce():
order by coalesce(lastname1, company_name)
I'm not sure what the other columns are contributing to the order by so I removed them.
EDIT:
If the values are blank or spaces and not NULL, then use case:
order by (case when trim(lastname1) = '' or lastname1 is null then company_name
else lastname1
end)
You could do this with this query:
select * from users
order by COALESCE(lastname1,company_name),lastname2,name ASC;
COALESCE takes the first non null element of it's list.
DEMO
If as in the modified question empty strings should be considered equally to NULL then you could do this with
select * from users
order by
CASE
WHEN TRIM(lastname1) = '' THEN company_name
WHEN lastname1 IS NULL THEN company_name
ELSE lastname1
END;
Demo

Pair SQL records without Cursor

I am trying to pair records in a SQL table, my table looks similar to this:
UID DATE TIME MateID
---------------------------------------
1 2013-06-07 08:00 NULL
2 2013-06-07 10:00 NULL
3 2013-06-07 13:00 NULL
4 2013-06-07 17:00 NULL
5 2013-06-08 07:00 NULL
6 2013-06-08 11:00 NULL
7 2013-06-08 14:00 NULL
8 2013-06-08 18:00 NULL
I know I can do this with a cursor, but I wanted to know if there was a set based solution that could give me this output:
UID DATE TIME MateID
---------------------------------------
1 2013-06-07 08:00 2
2 2013-06-07 10:00 1
3 2013-06-07 13:00 4
4 2013-06-07 17:00 3
5 2013-06-08 07:00 6
6 2013-06-08 11:00 5
7 2013-06-08 14:00 8
8 2013-06-08 18:00 7
The UID field won't be consecutive, the records will be ordered by DATE and TIME. The table will contain about 50k records
Edit: Sorry I should have been a bit more clear. MateID is the UID of the previous/next record. Records are grouped based on the DATE and ordered by TIME ASC, so the first record and the second record of the DATE are pairs, the third record and fourth record of the DATE are paired too. Please let me know if you need me to explain anything else. There will always be an even number of records per date.
Thanks
You can use ROW_NUMBER() and some simple maths to generate PairIDs:
declare #Tab table (UID int not null,Date date not null,time time not null)
insert into #Tab (UID,Date,Time) values
(1,'20130607','08:00'),
(2,'20130607','10:00'),
(3,'20130607','13:00'),
(4,'20130607','17:00'),
(5,'20130608','07:00'),
(6,'20130608','11:00'),
(7,'20130608','14:00'),
(8,'20130608','18:00')
;With PairedRows as (
select UID,Date,Time,
(ROW_NUMBER() OVER (ORDER BY Date,Time) + 1) / 2 as PairID
from #Tab
)
select p1.UID,p1.Date,p1.Time,p2.UID
from
PairedRows p1
inner join
PairedRows p2
on
p1.PairID = p2.PairID and
p1.UID != p2.UID
(I've done this as a SELECT, but it's easy enough to switch it to an UPDATE if this is meant to be a permanent pairing - it's not really clear from your question)
It may better match your model to PARTITION BY Date and only ORDER BY Time in the ROW_NUMBER() function - but since in this case you've stated that every date has an even number of rows, and all we care about are those rows which are assigned the same PairID without caring about the numeric value, it shouldn't affect the result of the query.
But it may better document your requirements.

split table into multiple tables based on not null criteria in sqlserver/ssis

I have a scenario where i have an input table table (Dynamic Table number of columns are not fixed) like below and need to get multiple tables based on not null values
Input table
ID Name Mobile Year value
1 john 1238769 2001 35
2 tommy 3423456 2001 56
3 smith 8761934 2007 65
4 NULL 4783921 2005 78
5 robert 8549543 2008 18
6 mary 5648404 2011 40
7 NULL 6729113 2003 59
8 NULL NULL 2006 10
9 cathy NULL 2010 35
10 jessi NULL 2012 45
So i need something like below tables based on not null
Output table1
ID Name Mobile Year value
1 john 1238769 2001 35
2 tommy 3423456 2001 56
3 smith 8761934 2007 65
5 robert 8549543 2008 18
6 mary 5648404 2011 40
output table 2
ID Mobile Year value
4 4783921 2005 78
7 6729113 2003 59
output table3
ID Name Year value
9 cathy 2010 3578
10 jessi 2012 45
and finally output table 4
ID Year value
8 2006 10
INSERT INTO OutputTable1
SELECT yourtable.*
FROM yourtable
WHERE Name IS NOT NULL and Mobile IS NOT NULL
INSERT INTO OutputTable2
SELECT yourtable.*
FROM yourtable
WHERE Name IS NULL and Mobile IS NOT NULL
INSERT INTO OutputTable3
SELECT yourtable.*
FROM yourtable
WHERE Name IS NOT NULL and Mobile IS NULL
INSERT INTO OutputTable4
SELECT yourtable.*
FROM yourtable
WHERE Name IS NULL and Mobile IS NULL
Since the number of columns is unknown (as well as their names, probably), you'll have to use dynamic SQL. Assuming the input table has a PK and the PK's name is either known beforehand or can somehow be determined easily, here's one approach to solving the problem:
Query metadata to determine the table's column names.
Using the list of names, build and execute a query that would:
unpivot all the data (non-PK) columns (converting them all into strings, apparently);
group the unpivoted result set by the PK and GROUP_CONCAT the names into two lists:
1) columns with non-null values, in the form of 'name1,name2,...', as SelectList,
2) columns with null values, like this: 'name1 IS NULL AND name2 IS NULL AND ...', as NullCondition;
Using distinct SelectList and NullCondition values from the last result set and the following template, build a series of queries to retrieve data from the original table:
' SELECT ' + SelectList +
' FROM yourtable' +
' WHERE ' + NullCondition
I'm not sure in which of the two products (SQL Server or MySQL) it would be more convenient to implement the above. It is true that SQL Server doesn't have a dedicated aggregate concatenation function like MySQL's GROUP_CONCAT. Workarounds are not unknown, though. MySQL, on the other hand, doesn't support this very handy UNPIVOT clause that SQL Server has. But again, alternatives to using UNPIVOT exist as well.