交换MySQL数据库中的记录

I have the following table in a mysql db:

CREATE TABLE IF NOT EXISTS `user_defaults` (
  `user_id` int(10) unsigned NOT NULL,
  `i1` text,
  `i2` text,
  `i3` text,
  `i4` text,
  `i5` text,
  `i6` text,
  `i7` text,
  `i8` text,
  `i9` text,
  `i10` text,
  `row` int(11) NOT NULL DEFAULT '0',
  `graphkind` varchar(20) CHARACTER SET utf8 COLLATE utf8_swedish_ci NOT NULL DEFAULT '',
  `graphtitle` varchar(255) CHARACTER SET utf8 COLLATE utf8_swedish_ci NOT NULL DEFAULT 'test',
  `keys` varchar(255) CHARACTER SET utf8 COLLATE utf8_swedish_ci NOT NULL,
  `vertical` int(11) NOT NULL DEFAULT '1',
  `size` varchar(255) NOT NULL DEFAULT '',
  `more1` varchar(255) NOT NULL DEFAULT '',
  `more2` varchar(255) NOT NULL DEFAULT '',
  PRIMARY KEY (`user_id`,`row`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT;

And some data for it:

INSERT INTO `user_defaults` (`user_id`, `i1`, `i2`, `i3`, `i4`, `i5`, `i6`, `i7`, `i8`, `i9`, `i10`, `row`, `graphkind`, `graphtitle`, `keys`, `vertical`, `size`, `more1`, `more2`) VALUES
(2, 'YEAR|Y.E. Q1F15', 'AREA|TOTAL ITALY', 'MOMENT|TOTALE MOMENTO', 'OFF PREMISE|OFF PREMISE§ON PREMISE|ON PREMISE§TOTAL|ON+OFF PREMISE', 'TOTAL|TOTAL PACKS', 'OCCASION|TOTAL OCCASION', 'BEER BY BRAND|BECK''S§BEER BY BRAND|DREHER§BEER BY BRAND|HEINEKEN§BEER BY BRAND|MORETTI§BEER BY BRAND|NASTRO AZZURRO§BEER BY BRAND|PERONI§BEER BY BRAND|TOURTEL', 'MEASURES|CONSUMERS 18+ (.000)§MEASURES|PENETRATION VS UNIVERSE§MEASURES|VOLUME (HL)', NULL, NULL, 1, 'col', 'Test', 'i1,i2,i3,i5,i6,i8,i4,i7', 1, '', '', ''),
(2, 'YEAR|Y.E. Q1F15', 'AREA|TOTAL ITALY', 'MOMENT|TOTALE MOMENTO', 'TOTAL|ON+OFF PREMISE', 'TOTAL|TOTAL PACKS', 'OCCASION|TOTAL OCCASION', 'TOTAL|TOTAL BEVERAGE', 'MEASURES|CONSUMERS 18+ (.000)', NULL, NULL, 2, 'line', 'Test', 'i1,i2,i4,i3,i5,i6,i8,i7', 1, '', '', ''),
(2, 'YEAR|Y.E. Q1F15', 'AREA|TOTAL ITALY', 'MOMENT|TOTALE MOMENTO', 'TOTAL|ON+OFF PREMISE', 'TOTAL|TOTAL PACKS', 'OCCASION|TOTAL OCCASION', 'BEER BY BRAND|TOTAL BEER BY BRAND§BEER BY BRAND|PERONI§BEER BY BRAND|MORETTI§BEER BY BRAND|NASTRO AZZURRO§BEER BY BRAND|HEINEKEN§BEER BY BRAND|BECK''S§BEER BY BRAND|DREHER§BEER BY BRAND|TOURTEL', 'MEASURES|CONSUMERS 18+ (.000)', NULL, NULL, 3, 'col', 'Pippe poppe peppe', 'i1,i2,i4,i3,i6,i5,i8,i7', 4, 's50', '', ''),
(12, 'TRIM|Q1 F13§TRIM|Q2 F13§TRIM|Q3 F13§TRIM|Q4 F13', 'AREA|TOTAL ITALY', 'BEER|BEER§BEER|PERONI', 'TOTAL|TOTAL PLACES', 'OCCASION|CONSUMPTION TOTAL OCCASION', 'MEASURE|VOLUMIZ', NULL, NULL, NULL, NULL, 1, 'col', 'Overview', 'i3,i2,i4,i5,i6,i1', 1, '', '', ''),
(13, 'TRIM|Q1 F13§TRIM|Q2 F13§TRIM|Q3 F13§TRIM|Q4 F13', 'AREA|TOTAL ITALY', 'BEER|BEER§BEER|PERONI', 'TOTAL|TOTAL PLACES', 'OCCASION|CONSUMPTION TOTAL OCCASION', 'MEASURE|VOLUMIZ', NULL, NULL, NULL, NULL, 1, 'col', 'Overview', 'i3,i2,i4,i5,i6,i1', 1, '', '', ''),
(35, 'QUARTER|Q1F15', 'AREA|TOTAL ITALY', 'MOMENT|TOTALE MOMENTO', 'OFF PREMISE|OFF PREMISE§ON PREMISE|ON PREMISE§TOTAL|ON+OFF PREMISE', 'TOTAL|TOTAL PACKS', 'OCCASION|TOTAL OCCASION', 'BEVERAGE ON+OFF|APERITIVES§BEVERAGE ON+OFF|BEER§BEVERAGE ON+OFF|CSD§BEVERAGE ON+OFF|FRUIT JUICES§BEVERAGE ON+OFF|OTHER BEVERAGE§BEVERAGE ON+OFF|PROSECCO, CHAMPAGNE§BEVERAGE ON+OFF|RTD TEA§BEVERAGE ON+OFF|SPIRITS+COCKTAIL§BEVERAGE ON+OFF|SPORT+ENERGY DRINKS§BEVERAGE ON+OFF|TOTAL BEVERAGE ON+OFF§BEVERAGE ON+OFF|WATER§BEVERAGE ON+OFF|WINE§TOTAL|TOTAL BEVERAGE', 'MEASURES|CONSUMERS 18+ (.000)§MEASURES|PENETRATION VS UNIVERSE§MEASURES|VOLUME (HL)', NULL, NULL, 2, 'line', 'Beverage - SHARE OFF STOMACH', 'i1,i2,i7,i4,i3,i6,i5,i8', 1, '', '', ''),
(35, 'QUARTER|Q1F15', 'AREA|TOTAL ITALY', 'MOMENT|TOTALE MOMENTO', 'OFF PREMISE|OFF PREMISE§ON PREMISE|ON PREMISE§TOTAL|ON+OFF PREMISE', 'TOTAL|TOTAL PACKS', 'OCCASION|TOTAL OCCASION', 'BEER BY BRAND|BECK''S§BEER BY BRAND|DREHER§BEER BY BRAND|HEINEKEN§BEER BY BRAND|MORETTI§BEER BY BRAND|NASTRO AZZURRO§BEER BY BRAND|PERONI§BEER BY BRAND|TOTAL BEER BY BRAND§BEER BY BRAND|TOURTEL', 'MEASURES|CONSUMERS 18+ (.000)§MEASURES|PENETRATION VS UNIVERSE§MEASURES|VOLUME (HL)', NULL, NULL, 3, 'line', 'Beer - SHARE OFF STOMACH', 'i1,i2,i7,i4,i3,i6,i5,i8', 1, '', '', '');

The relevant fields that identify a record are user_id and row, and I wrote a PHP editor that lets a user modify records as he wants. Records of a certain user (user_id) are shown and sorted by the "row" field.

Now I have added "MOVE UP"/"MOVE DOWN" buttons to swap two records together.

Essentially I only need to swap the "row" fields of two records:

UPDATE user_defaults SET row=1 WHERE user_id=xxx AND row=2
UPDATE user_defaults SET row=2 WHERE user_id=xxx AND row=1

of course this won't work as after the first line I would have both records with row=1 (an error as keys are unique) and after the second line they would both end up with row=2

My question: is there a way I can swap rows with SQL (or PHP) at the same time? Possibly keeping the query independent of the number and kind of fields in the table (except user_id and row)?

I mean, if possible, not like this:

UPDATE user_defaults SET i1=..,i2=..,i3=... WHERE user_id=xxx AND row=1
// (values from row 2)
UPDATE user_defaults SET i1=..,i2=..,i3=... WHERE user_id=xxx AND row=2
// (values from row 1)

(copy all the fields of one row into the other except row, but I would have to write all fields in the query and modify it every time a field is added..)