Is it possible to coalesce the same value? - sql-server

I ran into this problem because I'm using grouping sets in a subquery that gives me this results
name | objective | vehicle | count_of_installed
------------------------------------------------------
Antonio | | | 1
Antonio | 40 | 2nd vehicle | 19
Antonio | NULL | NULL | 20
George | | | 10
George | 50 | 2nd vehicle | 20
George | NULL | NULL | 30
And I'm then only searching only for rows where there are nulls, as they are the correct count_of_installed, now I want to have the correct objective and vehicle replacing the NULL values with the correct values, so I thought of something like coalesce(objective, objective), but I'm not sure this works.
For reference, my grouping sets are:
grouping sets (name, (name, objective, vehicle))
Edit 1
In my example above is the result of a query with joining my seller and sales tables, it shouldn't show neither blank nor null values, so when I say coalesce(objective, objective), I mean replace the null results from the result table with the correct values from my seller table.

Related

Can I prioritize sort columns in SQL based on an external table

I am working with a table that has several columns that potentially could be sorted based on a user setting. I am trying to come up with a way that avoids dynamic SQL and storing a sort string in a preference table.
An example of the data I am working with:
User | VIP | Date | Priority | Location
---------------------------------------------------
Jim | 1 | 1/1/2019 | 0 | 105
Joe | 0 | 2/1/2019 | 0 | 104
Jack | 1 | 1/5/2019 | 1 | 105
John | 0 | 2/6/2019 | 1 | 106
Jane | 0 | 4/1/2019 | 1 | 105
Jake | 1 | 7/1/2019 | 0 | 105
The sort table would look something like this
Column | SortOrder | Location
------------------------------------
VIP | 2 | 105
Date | 1 | 105
Priority | -1 | 105
VIP | 1 | 104
Date | 2 | 104
Priority | 3 | 104
VIP | 1 | 106
Date | -1 | 106
Priority | 2 | 106
My query would be using location as a where clause, so i would only be returning values for a specific location, but I would like to sort the data for that location based on the values set in the sort table.
-1 would be an inactive sort, so if the location was 105, I would want to order by Date then VIP. If 104, VIP, then Date, Then Priority and if 106 VIP then Priority without Date being considered.
I was thinking I could maybe do some kind of math thing, but I am having a hard time coming up with an algorithm.
I am trying to avoid hard coding Date ASC, VIP ASC into a table and retrieving it and applying it via Dynamic SQL (though I do have that working, but I am hoping for a better, Non Dynamic, solution).
Anyone have any suggestions?
You can't do this with math.
You can either use dynamic SQL, as you mentioned, or use a bunch of CASES.
First you would need to either PIVOT or use Subqueries or some other method to get virtual SortOrder columns for each of the columns you might ORDER BY. Then you could do something like this:
ORDER BY CASE
WHEN [VipSortOrder]=1 THEN [VIP]
WHEN [DateSortOrder]=1 THEN [Date]
WHEN [PrioritySortOrder]=1 THEN [Priority]
END,
CASE {Same for the 2's} etc...
If it were me, I'd use dynamic sql, personally.

TSQL Multiple column unpivot with named rows possible?

I know there are several unpivot / cross apply discussions here but I was not able to find any discussion that covers my problem. What I've got so far is the following:
SELECT Perc, Salary
FROM (
SELECT jobid, Salary_10 AS Perc10, Salary_25 AS Perc25, [Salary_Median] AS Median
FROM vCalculatedView
WHERE JobID = '1'
GROUP BY JobID, SourceID, Salary_10, Salary_25, [Salary_Median]
) a
UNPIVOT (
Salary FOR Perc IN (Perc10, Perc25, Median)
) AS calc1
Now, what I would like is to add several other columns, eg. one named Bonus which I also want to put in Perc10, Perc25 and Median Rows.
As an alternative, I also made a query with cross apply, but here, it seems as if you can not "force" sort the rows like you can with unpivot. In other words, I can not have a custom sort, but only a sort that is according to a number within the table, if I am correct? At least, here I do get the result like I wish to have, but the rows are in a wrong order and I do not have the rows names like Perc10 etc. which would be nice.
SELECT crossapplied.Salary,
crossapplied.Bonus
FROM vCalculatedView v
CROSS APPLY (
VALUES
(Salary_10, Bonus_10)
, (Salary_25, Bonus_25)
, (Salary_Median, Bonus_Median)
) crossapplied (Salary, Bonus)
WHERE JobID = '1'
GROUP BY crossapplied.Salary,
crossapplied.Bonus
Perc stands for Percentile here.
Output is intended to be something like this:
+--------------+---------+-------+
| Calculation | Salary | Bonus |
+--------------+---------+-------+
| Perc10 | 25 | 5 |
| Perc25 | 35 | 10 |
| Median | 27 | 8 |
+--------------+---------+-------+
Do I miss something or did I something wrong? I'm using MSSQL 2014, output is going into SSRS. Thanks a lot for any hint in advance!
Edit for clarification: The Unpivot-Method gives the following output:
+--------------+---------+
| Calculation | Salary |
+--------------+---------+
| Perc10 | 25 |
| Perc25 | 35 |
| Median | 27 |
+--------------+---------+
so it lacks the column "Bonus" here.
The Cross-Apply-Method gives the following output:
+---------+-------+
| Salary | Bonus |
+---------+-------+
| 35 | 10 |
| 25 | 5 |
| 27 | 8 |
+---------+-------+
So if you compare it to the intended output, you'll notice that the column "Calculation" is missing and the row sorting is wrong (note that the line 25 | 5 is in the second row instead of the first).
Edit 2: View's definition and sample data:
The view basically just adds computed columns of the table. In the table, I've got Columns like Salary and Bonus for each JobID. The View then just computes the percentiles like this:
Select
Percentile_Cont(0.1)
within group (order by Salary)
over (partition by jobID) as Salary_10,
Percentile_Cont(0.25)
within group (order by Salary)
over (partition by jobID) as Salary_25
from Tabelle
So the output is like:
+----+-------+---------+-----------+-----------+
| ID | JobID | Salary | Salary_10 | Salary_25 |
+----+-------+---------+-----------+-----------+
| 1 | 1 | 100 | 60 | 70 |
| 2 | 1 | 100 | 60 | 70 |
| 3 | 2 | 150 | 88 | 130 |
| 4 | 3 | 70 | 40 | 55 |
+----+-------+---------+-----------+-----------+
In the end, the view will be parameterized in a stored procedure.
Might this be your approach?
After your edits I understand, that your solution with CROSS APPLY would comes back with the right data, but not in the correct output. You can add constant values to your VALUES and do the sorting in a wrapper SELECT:
SELECT wrapped.Calculation,
wrapped.Salary,
wrapped.Bonus
FROM
(
SELECT crossapplied.*
FROM vCalculatedView v
CROSS APPLY (
VALUES
(1,'Perc10',Salary_10, Bonus_10)
, (2,'Perc25',Salary_25, Bonus_25)
, (3,'Median',Salary_Median, Bonus_Median)
) crossapplied (SortOrder,Calculation,Salary, Bonus)
WHERE JobID = '1'
GROUP BY crossapplied.SortOrder,
crossapplied.Calculation,
crossapplied.Salary,
crossapplied.Bonus
) AS wrapped
ORDER BY wrapped.SortOrder

Inserting 1 or multiple rows into a table from the results of a select query

I'm writing a stored procedure to insert single or multiple rows from a table to the same table again with some modifications.
It is not clear how many rows will be inserted, it can be only one or 10. I need to insert them all with some fields changed.
I looked at other questions but couldn't find anything help with my unclear number of rows problem.
Can I just take the results into a temporary table and do my modifications, then insert them to the table again? Would it work on this 1 or n number of rows?
EDIT:
Example
There are 6 rows with same idenfitifier. (Actual table contains 36 columns, I'm using these 5 as an example)
+-----+--------+------------+-------------------------+----------+
| Id | NctsId | BeyanIndex | CancelDate | LRN |
+-----+--------+------------+-------------------------+----------+
| 263 | 97 | NULL | NULL | NULL |
| 264 | 97 | NULL | 2015-11-02 12:38:15.953 | MULTI |
| 265 | 97 | 0 | NULL | NULL |
| 266 | 97 | 1 | NULL | NULL |
| 267 | 97 | 0 | 2015-11-02 12:38:15.953 | test1313 |
| 268 | 97 | 1 | 2015-11-02 12:34:32.060 | test1414 |
+-----+--------+------------+-------------------------+----------+
I need to take the ones with the ID's 264,267 and 268.
These Id's are the result of a select of course, they are based on some criteria.
Then I need to insert them again into same table with some modifications on the ones with the ID's 267 and 268.
So far only a temp table and a ##rowcount feels like right in handling this to me.
If you can identify the rows to be processed with a WHERE clause and create the modified versions in a SELECT query, then you can use INSERT...SELECT, which will do 0 or more rows depending on how many meet the WHERE specification.
INSERT tbl (col1, ...)
SELECT
CASE
WHEN something THEN modified-column-expression
WHEN something-else ...
END col1
, ...
FROM tbl
WHERE id in (list-of-affected-ids)
This seems to be what you need, but you are suggesting not...what have I missed?

Unpivot SQL each row in SQL table to key-value pairs with group IDs

Running SQL Server 2012, I have a table in the following format:
ENC_ID | Name | ED_YN | Seq
-------------------------------------
1234 | John | Y | 1
1234 | Sally | N | 2
2345 | Chris | N | 1
2345 | Sally | N | 2
I would like to unpivot this into a entity-attribute-value list (if that's the right terminology - I am thinking of them as key-value pairs grouped by IDs), with the following format:
ENC_ID | Seq | Key | Value
--------------------------------------
1234 | 1 | Name | John
1234 | 1 | ED_YN | Y
1234 | 2 | Name | Sally
1234 | 2 | ED_YN | N
2345 | 1 | Name | Chris
2345 | 1 | ED_YN | N
2345 | 2 | Name | Sally
2345 | 2 | ED_YN | N
I have seen various answers to this using UNION or UNPIVOT, but these solutions tend to be long and must be closely customized to the table. I'm looking for a solution that can be reused without a great deal of rewriting as this pattern solves a problem I expect to run into frequently (ingesting data from star-schema into Tableau via extracts, where I don't necessarily know the number of value columns).
The closest thing I've found to solve this is this question/answer but I haven't had success altering the solution to add ENC_ID and Seq to each row in the result table.
Thanks.
I will use Cross Apply with table valued Constructor to do this unpivoting
select ENC_ID, Seq, Key, Value
from yourtable
cross apply
(values ('Name',Name),
('ED_YN',ED_YN)) CS (Key,Value)
You can try below query. This uses classic UNPIVOT syntax.
Since I am unsure about your column types I have casted both of them as varchar(100). You can increase length from 100.
Working sql fiddle demo link :
select enc_id,seq, k [key],v [value] from
(select enc_id,seq,cast(name as varchar(100)) as name, cast(ed_yn as varchar(100)) as ed_yn from r)s
UNPIVOT
( v for k in ([name],[ed_yn])
)up

SQL Server - tricky query to update contact id using ROW_NUMBER to reference index value

A previous developer used an index rather than the actual contactID to reference which of the associated contacts are the primary contact. The index works well when the app gets the contacts and sets the primary contact in the list on the page, but try joining for a report! Not easy; so I want to update the main table with the actual contact ID to make for a simple join and to avoid this buggary.
In this particular case, I need to update tblInquiry with the claimantContactID and agentContactID. Those two fields I just created and defaulted to 0. However, the challenge is to use the claimantContactIndex and agentContactIndex values from tblInquiry, to get the respective nth row from tblContacts. The index is 0 based, so if the index value is 2, then get the ID of the 3rd contact, for example.
Also, claimantContactIndex and agentContactIndex can either be NULL or some number. If NULL, then assume the first contact (index 0).
I will also add that the contacts index cannot have an order by on it because the application relies upon the natural order when getting the contacts list (there is no order by in the stored procedure), and selects then the index accordingly.
DB Platform: SQL Server 2008 R2 Express Edition.
I have the following table structure:
tblInquiry
id | claimantID | agentID | claimantContactIndex | agentContactIndex | claimantContactID | agentContactID
--------------------------------
1 | 1001 | 2001 | 2 | 0 | 0 | 0
2 | 1002 | NULL | 0 | NULL | 0 | 0
tblClaimant
id | name | address | phone | email
--------------------------------
1001 | Widgets Inc. | 123 W. Main | 5550000 | widgets#here.com
1002 | Thingies LLC. | 456 W. Main | 5551111 | thingies#here.com
tblAgent
id | name | address | phone | email
--------------------------------
2001 | Simon Bros. | 789 W. Main | 5552222 | simon#here.com
tblContacts
id | claimantID | agentID | fn | ln | phone | email
--------------------------------
3001 | 1001 | NULL | John | Doe | 5553333 | john#here.com
3002 | 1001 | NULL | Fred | Flynn | 5554444 | fred#here.com
3003 | 1001 | NULL | Mike | Brown | 55555555 | mike#here.com
3004 | 1001 | NULL | Susan | Pierce | 5556666 | susan#here.com
3005 | NULL | 2001 | Jeff | Bridges | 5557777 | jeff#here.com
3006 | NULL | 2001 | Karry | Sinclair | 5558888 | Karry#here.com
3007 | NULL | 2001 | Steve | Green | 5559999 | steve#here.com
3008 | NULL | 2001 | Peter | White | 5550001 | peter#here.com
Update:
I have worked out the select part of this solution and I can now get the correct claimant contact info using ROW_NUMBER() and a JOIN. I will add more to get correct agent contact info. I also handled the case where an index is NULL. And ultimately I will work this out to update the inquiry table now that I have the right contactID.
SELECT
i.id inquiryID, i.claimantContactIndex, i.agentContactIndex, i.claimantContactID, i.agentContactID
,r.id contactID, r.claimantID, r.agentID
,r.*
FROM
(
SELECT ROW_NUMBER()
OVER (Partition by con.claimantid Order by (SELECT NULL)) AS RowNumber, *
FROM tblContacts con
) r
INNER JOIN
tblInquiry i on i.claimantid = r.claimantid and ((isnull(i.claimantContactIndex, 0) + 1 = r.RowNumber ))
WHERE
i.id in (1, 2, 3, 4, 5)
ORDER BY
i.id
This issue was resolved by doing the following:
As I posted above, using ROW_NUMBER() and (SELECT NULL()) along with an isnull to handle null values to get the correct contacts.
I selected the results into a temp table.
I then updated the inquiry table by joining it to the temp table.
dropped temp table
I had to do this in two passes, once for claimants, a second time for agents.
Thx #EricH for pointing me in the right direction.
You could do something like:
Using ideas from here:
https://msdn.microsoft.com/en-us/library/ms186734.aspx
SELECT
ROW_NUMBER() OVER (Order by Id) AS RowNumber,
claimantID, agentID, (etc...)
FROM
tblContacts
To get an index based resultset. I'd drop it into a temp table and select from that where RowNumber = Whatever index you want.

Resources