How to transform table with several columns into a keyword table - sql-server-2014

I have a table with columns like CustID, FirstName, LastName, PhoneNumber, Membershiplevel, etc.
I want to produce a table with these columns: CustID, Keyword, Value.
The column names would be the keywords, and there would be a row for every keyword.
So this:
CustID, FirstName, LastName, PhoneNumber, MembershipLevel
1234 Joe Smith 555-555-5555, Select
Would become
CustID, Keyword , Value
1234 , FirstName , Joe
1234 , LastName , Smith
1234 , PhoneNumber, 555-555-5555
1234 , MembershipLevel, Select
I know I could painstakingly accomplish this using dynamic SQL, but is there a straightforward, "SQL" way to do this without resorting to procedural T-SQL?

use CROSS APPLY operator with VALUES constructor
select a.*
from tbl
cross apply
(
values
(CustID, 'FirstName', FirstName),
(CustID, 'LastName', FirstName),
(CustID, 'PhoneNumber', PhoneNumber),
(CustID, 'MembershipLevel',MembershipLevel)
) a (CustID, KeyWord, Value)

Related

How to assign value of SQL query to a MySQL table column

I have two MySQL tables, g734 and g8internal. I ran an SQL SELECT query given below in which I would like to put the result of the query to the Maths field and Total_Score field in table g8internal. The fields in g734 and g8internal are uniform. They are StudentID, FirstName, LastName, Maths and Total_Score. Please have a look at my SQL code below. The one I have is giving SQL syntax error in phpMyAdmin. I would like to store the result of the query to Total_Score and Maths in g8internal.
SELECT StudentID, FirstName, LastName, SUM(Total_Score) AS T_Score, SUM(Maths) AS Mth
FROM
(
SELECT StudentID, FirstName, LastName, Total_Score, Maths FROM g734
UNION ALL
SELECT StudentID, FirstName, LastName, Total_Score, Maths FROM g8internal
) t on g8internal.FirstName = g734.FirstName AND g8internal.LastName = g734.LastName
GROUP BY StudentID, FirstName, LastName
SET g8internal.Total_Score = T_Score,
g8internal.Maths = Mth
Try the query like this and see if it works. And i dont think you need to join with FirstName and LastName if Student Id works as key.
update
g8internal g8int
join
(
select
t.StudentID,
t.FirstName,
t.LastName,
SUM(t.Total_Score) AS T_Score,
SUM(t.Maths) AS Mth
from
(
SELECT
StudentID,
FirstName,
LastName,
Total_Score,
Maths
FROM
g734
UNION ALL
SELECT
StudentID,
FirstName,
LastName,
Total_Score,
Maths
FROM
g8internal
) t
group by
t.StudentID,
t.FirstName,
t.LastName
) t1 on g8int.StudentID = t1.StudentID
and g8int.FirstName = t1.FirstName
and g8int.LastName = t1.LastName
set
g8int.Total_Score = t1.T_Score,
g8int.Maths = t1.Mth
Reference : MySQL - UPDATE query based on SELECT Query
Thanks

INSERT INTO using subquery

Q: Insert a customer Jake Smith who’s shipping address is “yknhl fr hluhw” and people can reach him at ‘1236548780’ & ‘jakesmith#email.com’ (use a sub query to get the address).
The shipping address is in another table called shipping_details, which can be referenced using the shipping_id_details column.
I am unable to get it right.
INSERT INTO assignment2.customers(first_name, last_name, email, phoneNo, shipping_details_id)
VALUES('Jake', 'Smith', 'jakesmith#email.com', '1236548780',
SELECT FROM assignment2.shipping_details
WHERE address = 'yknhl fr hluhw'))
Table structures:
assignment2.customers
(customer_id, first_name, last_name, email, phoneNo, shipping_detail_id)
assignment2.shipping_details
(shipping_detail_id, address, city, province)
Ignoring the part about a subquery, below is a sample query. For further help, see Why should I provide a Minimal Reproducible Example for a very simple SQL query?
INSERT INTO assignment2.customers
(first_name
, last_name
, email
, phoneNo
, shipping_details_id
)
SELECT 'Jake'
, 'Smith'
, 'jakesmith#email.com'
, '1236548780',
, x.shipping_details_id
FROM assignment2.shipping_details x
WHERE x.address = 'yknhl fr hluhw'
-- LIMIT 1
You need to change your query like following...
INSERT
INTO assignment2.customers(
first_name
, last_name
, email
, phoneNo
, shipping_details_id
)
VALUES (
'Jake'
, 'Smith'
, 'jakesmith#email.com'
, '1236548780'
, (
SELECT
shipping_detail_id
FROM
assignment2.shipping_details
WHERE
address = 'yknhl fr hluhw'
)
)

Use another query with the same result

I have query:
SELECT Name, Surname, Telephone, PersonID FROM Client WHERE Telephone =
(SELECT MAX(Telephone) FROM Client) OR PersonID = (SELECT MAX(PersonID)
FROM Client);
With result:
| Name | Surname | Telephone | PersonID |
| Tyler | Henry | 998778781 | 38568215856 |
| Brooke | Thornton | 617196573 | 99412132661 |
What other query will give me the same result? I have to compare two queries in terms of optimization.
You can use a UNION optimization:
SELECT Name, Surname, Telephone, PersonID
FROM Client
WHERE Telephone = (SELECT MAX(Telephone) FROM Client)
UNION
SELECT Name, Surname, Telephone, PersonID
FROM Client
WHERE PersonID = (SELECT MAX(PersonID) FROM Client)
If a subset of selected columns is UNIQUE, the query will return the same result.
Given indexes on (Telephone) and (PersonID) the query should also be much faster on a big table. The reason is that MySQL is not able to use more than one index per table and (sub)query. Splitting the query in two subqueries will allow the engine to use both indexes.
You can get the max Telephone and max PersonID in a single query and then join it to the table:
SELECT c.Name, c.Surname, c.Telephone, c.PersonID
FROM Client c INNER JOIN (
SELECT MAX(Telephone) Telephone, MAX(PersonID) PesronID FROM Client
)m ON m.Telephone = c.Telephone OR m.PersonID = c.PersonID
or with NOT EXISTS:
SELECT Name, Surname, Telephone, PersonID FROM Client c
WHERE
NOT EXISTS (
SELECT 1 FROM Client
WHERE Telephone > c.Telephone
)
OR
NOT EXISTS (
SELECT 1 FROM Client
WHERE PersonID > c.PersonID
)
It depends on what indexes you have. Without INDEX(Telephone) and INDEX(PersonID) most of the answers will do table scan(s).
Here's another contender:
( SELECT Name, Surname, Telephone, PersonID
FROM Client
ORDER BY Telephone DESC LIMIT 1 )
UNION DISTINCT
( SELECT Name, Surname, Telephone, PersonID
FROM Client
ORDER BY PersonID DESC LIMIT 1 )
This may be faster because it does not have subqueries. However, it may give different results if two have the same Telephone or PersonID.
I suggest you run all the formulations against your data to see which is best.
If you want to discuss things further, please provide SHOW CREATE TABLE client and EXPLAIN SELECT ... -- both will give clues of what will/won't run faster.

Union shortcut for 2 columns of table and identical query?

So imagine a table that consists of first, middle and last names.
I want to write a query that, returns all the middle and first names, as 1 column, of people whose last name presents an entirely arcane, complicated quality that requires 20 nested subqueries or so to determine.
One way to do that is
Select FirstName From Names Where LastName in (HISTSNEROIP)
Union
Select MiddleName From Names Where LastName in (HISTSNEROIP)
Where HISTSNEROIP stands for 'huge inefficient subquery that should not even run once if possible'. As the name would imply, running it twice as above is a big no-no.
Ideally, I would do something like
Select FirstName and MiddleName from names where Lastname in (HISTSNEROIP)
Where 'and' is replaced by whatever tool eludes me.
Something like this should work..
SELECT f_m
FROM (
SELECT FirstName as f_m, LastName FROM names
UNION
SELECT MiddleName as f_m, LastName FROM names
) as T
WHERE T.LastName in (HISTSNEROIP);
You can use a CTE:
with cte (
HISTSNEROIP
)
select firstname from names where lastname in cte
union all
select middlename from names where lastname in cte
This way HISTSNEROIP runs only once.
Why wouldn't you select this in one query?
Select FirstName, MiddleName
From Names
Where LastName in (HISTSNEROIP)
If you need, you can unpivot this:
Select (case when x.n = 1 then FirstName else MiddleName end)
From Names n cross join
(select 1 as n union all select 2 as n) x
Where LastName in (HISTSNEROIP)

How to create a test query from a function?

Having trouble producing more than one row from this query. I want to include more samples in my test query. Maybe 2 more names to test so that my output. I think I could use UNION ALL but not sure.
This consist of 3 columns and 1 row, but I want 2 more samples adding 2 more rows:
select tstName, AnticipatedValue, a_testbed.NameFormat('F', 'Clark', 'John') as "name"
from (
select 'Clark, John' as tstName, 'John Clark' as AnticipatedValue ) as tstTbl#
The function has three input parameters. The first is a 'F' which formats names as firstName lastName, the second and third parameters are strings which are the last and first names.
you could accomplish with UNION
SELECT tstName, AnticipatedValue,
a_testbed.NameFormat('F', firstName, lastName) as "name"
FROM (
SELECT 'Clark1' AS firstName, 'John1' as lastName, 'John Clark' as AnticipatedValue
UNION
SELECT 'Clark2' AS firstName, 'John2' as lastName, 'John Clark' as AnticipatedValue
UNION
SELECT 'Clark3' AS firstName, 'John3' as lastName, 'John Clark' as AnticipatedValue
) AS tstTbl#