SQL Query pivot approach assistance - sql

i am really struggling with this pivot and hoped reaching out for help and enlightenment might help.
Say i have the following table....
Table A
type actId date rowSort order value value_char colName
------------------------------------------------------------------------------------
checking 1003 2011-12-31 2 1 44 44 Amount
checking 1003 2011-12-31 2 2 55 55 Interest
checking 1003 2011-12-31 2 3 66 66 Change
checking 1003 2011-12-31 2 4 77 77 Target
checking 1003 2011-12-31 2 5 88 88 Spread
savings 23456 2011-12-31 1 1 999 999 Amount
savings 23456 2011-12-31 1 2 888 888 Interest
savings 23456 2011-12-31 1 3 777 777 Change
savings 23456 2011-12-31 1 4 666 666 Target
savings 23456 2011-12-31 1 5 555 555 Spread
And i want to transpose to table b
checking chkId date rowSort order chkvalue chkValchar colName savings savId savVal savValChar
-------------------------------------------------------------------------------------------------------------------
checking 1003 2011-12-31 2 1 44 44 Amount savings 23456 999 999
checking 1003 2011-12-31 2 2 55 55 Interest savings 23456 888 888
checking 1003 2011-12-31 2 3 66 66 Change savings 23456 777 777
checking 1003 2011-12-31 2 4 77 77 Target savings 23456 666 666
checking 1003 2011-12-31 2 5 88 88 Spread savings 23456 555 555
I can admit this is beyond my skills at the moment.
I believe i need to do a pivot on this table, using the rowSort (identify savings vs checking) along with ordering using the order column. This maybe wrong and that is why i am here.
Is a pivot the right way to go? Am i right to assume my pivot is to use the aggregate max(rowSort)?

Assuming rowSort from `checking equal to rowSort+1 from savings and the rows link though field value, this should do it:
SELECT DISTINCT
a.type as checking,
a.actId as chkId,
a.date,
a.rowSort+1,
a.order,
a.value as chkvalue,
a.value_char as chkValchar,
a.colName,
b.type as 'savings',
a.actId as savId,
b.value as savVal,
b.value_char as savValChar
FROM tablea a
INNER JOIN tablea b ON b.rowSort = a.rowSort+1 and b.value = a.value

Based on the requirements you presented, you will not use a PIVOT for this query, you will want to JOIN your table to itself. The query below should give you the records that you want without having to use a DISTINCT
select c.type as checking
, c.actId as chkid
, c.date
, c.rowsort
, c.[order]
, c.value as chkvalue
, c.value_char as chkValchar
, c.colName
, s.type as savings
, s.actId as savId
, s.value as savVal
, s.value_char as savValchar
from t1 c
inner join t1 s
on c.rowsort = s.rowsort + 1
and c.[order] = s.[order]
See SQL Fiddle with Demo

Related

Exclude rows where keys match, but are on different rows

I'm looking for the best way to produce the result set in the scenario provided. My cust3 column isn't identifying the repeated values in the indvid2 column. The end result I'm looking for is to exclude the rows where key1 and key2 match (ids:1,2,6 and 7), then sum accounts where the acctids match.If there's a better way to code this, I welcome all suggestions. Thanks!
WITH T10 as (
SELECT acctid,invid,(
case
when invid like '%-R' then left (InvID,LEN(invid) -2) else InvID
END) as InvID2
FROM table x
GROUP BY acctID,invID
),
T11 as (
SELECT acctid, Invid2, COUNT(InvID2) as cust3
FROM T10
GROUP BY InvID2,acctid
HAVING
COUNT (InvID2) > 1
)
select DISTINCT
a.acctid,
a.name,
b.invid,
C.invid2,
D.cust3,
b.amt,
b.key1,
b.key2
from table a
inner join table b (nolock) on a.acctid = b.acctid
inner join T10 C (nolock) on b.invid = c.invid
inner join T11 D (nolock) on C.invid2 = D.invid2
Resultset
id acctID name invid invid2 Cust3 amt key1 key2
1 123 James 101 101 2 $500 NULL 6789
2 123 james 101-R 101 2 ($500) 6789 NULL
3 123 James 102 102 2 $350 NULL NULL
4 123 James 103 103 2 $200 NULL NULL
5 246 Tony 98-R 98 2 ($750) 7423 NULL
6 432 David 45 45 2 $100 NULL 9634
7 432 David 45-R 45 2 ($100) 9634 NULL
8 359 Stan 39-R 39 2 ($50) 6157 NULL
9 753 George 95 95 2 $365 NULL NULL
10 753 George 108 108 2 $100 NULL NULL
Desired Resultset
id acctID name invid invid2 Cust3 amt key1 key2
1 123 James 101 101 2 $500 NULL 6789
2 123 james 101-R 101 2 ($500) 6789 NULL
3 123 James 102 102 1 $350 NULL NULL
4 123 James 103 103 1 $200 NULL NULL
5 246 Tony 98-R 98 1 ($750) 7423 NULL
6 432 David 45 45 2 $100 NULL 9634
7 432 David 45-R 45 2 ($100) 9634 NULL
8 359 Stan 39-R 39 1 ($50) 6157 NULL
9 753 George 95 95 1 $365 NULL NULL
10 753 George 108 108 1 $100 NULL NULL
Then to sum amt by acctid
id acctid name amt
1 123 James $550
2 246 Tony ($750)
3 359 Stan ($50)
4 753 George $465
Something like:
;WITH Keys as (
SELECT Key1.acctID, [Key] = Key1.Key1
FROM YourTable as Key1
INNER JOIN YourTable as Key2
ON Key1.Key1 = Key2.Key2 and Key1.acctID = Key2.acctID
)
SELECT t.acctID, t.name, amt = SUM(t.amt)
FROM YourTable as t
LEFT JOIN Keys as k
ON t.acctID = k.acctID and (t.Key1 = [Key] or t.Key2 = [Key])
WHERE k.acctID is Null
GROUP BY t.acctID, t.name

SQL query to allow NULL for a highest_bid column when no bid has been placed yet

For school I need to make a function on an auction website. For this I need to join a couple of tables in a VIEW. This worked just fine, until I needed to add a filter for price range. Seems easy enough but the query result needs to allow a NULL when no bid has been placed.
The Statement for the View:
SELECT I.itemID, I.title, I.startPrice, B.highestBid, Cfi.category, I.endDate
FROM dbo.Items AS I INNER JOIN dbo.category_for_item AS Cfi ON V.itemID = Vir.itemID
LEFT OUTER JOIN dbo.Bid AS B ON V.itemID = B.itemID
This would get the following Table:
itemID title startPrice highestBid category endDate
1 1234 Alfa 25 26 PC 2018-09-22
2 1234 Alfa 25 NULL PC 2018-09-22
3 5678 Bravo 9 20 Console 2018-07-03
4 5678 Bravo 9 15 Console 2018-07-03
5 5678 Bravo 9 NULL Console 2018-07-03
6 9876 Charlie 84 100 Stamps 2018-06-14
7 9876 Charlie 84 90 Stamps 2018-06-14
8 9876 Charlie 84 85 Stamps 2018-06-14
9 9876 Charlie 84 NULL Stamps 2018-06-14
10 1470 Delta 98 100 Fashion 2018-06-15
11 1470 Delta 98 99 Fashion 2018-06-15
12 1470 Delta 98 NULL Fashion 2018-06-15
13 9631 Echo 56 65 Cars 2018-06-25
14 9631 Echo 56 NULL Cars 2018-06-25
15 7856 Foxtrot 98 NULL Dolls 2018-12-26
After looking around for answers I got a query for joining the VIEW on itself with only showing the highest bid instead of all bids:
SELECT VW.itemID, VW.title, VW.startPrice, VW.highestBid, VW.category, VW.endDate
FROM VW_SEARCH AS VW
INNER JOIN (SELECT itemID, MAX(highestBid) AS MaxBid
FROM VW_SEARCH
GROUP BY itemID) VJ
ON VW.itemID = VJ.itemID AND VW.highestBid = VJ.MaxBid
This gave the next results:
itemID title startPrice highestBid category endDate
1 1234 Alfa 25 26 PC 2018-09-22
2 5678 Bravo 9 20 Console 2018-07-03
3 9876 Charlie 84 85 Stamps 2018-06-14
4 1470 Delta 98 100 Fashion 2018-06-15
5 9631 Echo 56 65 Cars 2018-06-25
As I expected the result only showed the items with at least one bid on them. I tried added one extra condition on the subQuery and Joining RIGHT OUTER to make sure I would not get doubles of an itemID.
SELECT VW.itemID, VW.title, VW.startPrice, VW.highestBid, VW.category, VW.endDate
FROM VW_SEARCH AS VW
RIGHT OUTER JOIN (SELECT itemID, MAX(highestBid) AS MaxBid
FROM VW_SEARCH
WHERE highestBid > 0 OR highestBid IS NULL
GROUP BY itemID) VJ
ON VW.itemID = VJ.itemID AND VW.highestBid = VJ.MaxBid
This gave the following results (did not add result 5 - 1199 because it is all the same as result 4, this would happen in the actual table not the example table from above):
itemID title startPrice highestBid category endDate
1 1234 Alfa 25 26 PC 2018-09-22
2 5678 Bravo 9 20 Console 2018-07-03
3 9876 Charlie 84 85 Stamps 2018-06-14
4 NULL NULL NULL NULL NULL NULL
1200 1470 Delta 98 100 Fashion 2018-06-15
1201 9631 Echo 56 65 Cars 2018-06-25
While this is technicly allowing a NULL in the colums I need to get a result in the likes of :
itemID title startPrice highestBid catgory endDate
1 1234 Alfa 25 26 PC 2018-09-22
2 5678 Bravo 9 20 Console 2018-07-03
3 9876 Charlie 84 85 Stamps 2018-06-14
4 1470 Delta 98 100 Fashion 2018-06-15
5 9631 Echo 56 65 Cars 2018-06-25
6 7856 Foxtrot 98 NULL Dolls 2018-12-26
How do I get the desired result, or is it just impossible?
Also if the query could be written better, please say so.
Thanks in advance.
Solve the problem using a left join:
SELECT VW.itemID, VW.title, VW.startPrice, VW.highestBid, VW.category, VW.endDate
FROM VW_SEARCH VW LEFT JOIN
(SELECT itemID, MAX(highestBid) AS MaxBid
FROM VW_SEARCH
GROUP BY itemID
) VJ
ON VW.itemID = VJ.itemID AND VW.highestBid = VJ.MaxBid;
Or, use the ANSI-standard ROW_NUMBER() function:
select vw.*
from (select vw.*,
row_number() over (partition by itemID
order by highestBid nulls last
) as seqnum
from vw_search vw
) vw
where seqnum = 1;
This guarantees one row per item.
Note: Not all databases support NULLS LAST. This may not even be necessary, but you can also implement it using a case expression.
Can you give the definition of the view at least? Maybe the table definition too.
I would go only with subquery as because identity column :
select vw.*
from vw_search vw
where id = (select vm1.id
from vw_search vm1
where vm.itemID = vw1.itemID and vm1.highestBid is not null
order by vm1.highestBid desc
limit 1
);
However, some DBMS has not support LIMIT clause such as SQL Server if so, then you can use TOP clause instead.

How to find overlapping date ranges from same tables (multiple overlapping)

there are user data with data range
I'm trying to update flag section by using query. If same user id group overlap any single day range, it should say overlapping in flag section.
can you please give me some idea how to flag this overlapping data
Thanks
Text file format:
ID UserID registereddate termdate flag
1 abcd 1/1/2018 2/28/2018 overlapping with 2
2 abcd 1/1/2018 6/30/2018 overlapping with 1
3 abcd 8/1/2018 12/31/2018
4 bbbb 5/1/2018 6/30/2018 overlapping with 5
5 bbbb 6/1/2018 7/30/2018 overlapping with 4
6 bbbb 9/1/2018 9/30/2018
7 bbbb 10/1/2018 10/30/2018
8 bbbb 11/1/2018 11/30/2018
9 ccccc 7/1/2018 9/30/2018 overlapping with 10
10 ccccc 9/1/2018 12/31/2018 overlapping with 9
11 dddd 8/1/2018 8/31/2018
12 dddd 12/1/2018 12/31/2018
13 eeee 9/1/2018 12/31/2018 overlapping with 17
14 eeee 8/1/2018 8/31/2018
15 eeee 9/1/2018 9/30/2018 overlapping with 15
To get 'overlapping', use exists:
select t.*,
(case when exists (select 1
from t t2
where t2.registereddate < t.termdate and
t2.termdate > t.registereddate
)
then 'overlaps'
end)
from t;
In an update, this looks like:
update t
set flag = 'overlaps'
where exists (select 1
from t t2
where t2.registereddate < t.termdate and
t2.termdate > t.registereddate
);
Getting the list of overlapping records in a string field is much, much more complicated in SQL Server. Getting a pairwise list of overlaps is pretty easy.
You could also inner join the table onto itself and compare the dates that way
SELECT *
FROM [Table] t1
INNER JOIN [Table] t2
ON t1.ID <> t2.ID
AND t1.UserId = t2.UserId
AND ((t1.RegisterDate BETWEEN t2.RegisterDate AND t2.TermDate) OR (t1.TermDate BETWEEN t2.RegisterDate AND t2.TermDate))
Although the more field you end up having the more complicated this becomes
See this DBFiddle

SQL Syntax to group this data in SQL Server 2012

I have a table (called StayDate) which looks like this:
ResaID Date RoomCategory RateAmount
1 2014-09-01 A 125
1 2014-09-02 A 125
1 2014-09-03 B 140
2 2014-09-04 A 125
2 2014-09-05 A 125
2 2014-09-06 A 125
2 2014-09-07 C 160
2 2014-09-08 C 160
The output from the SQL syntax I'm after need to look like this:
ResaID Count RoomCategory RateAmount
1 2 A 125
1 1 B 140
2 3 A 125
2 2 C 160
Can anyone help with the SQL syntax needed to summarize the data as above?
A way to do this without a GROUP BY:
SELECT DISTINCT ResaID, COUNT(*) OVER (PARTITION BY ResaID, RoomCategory, RateAmount) Count, RoomCategory, RateAmount
FROM StayDate

Select max date No result I want

SELECT
mat.matid,
MAX (to_date(to_char (matdatetable.matdateupdate,'yyyy-mm-dd'),'yyyy-mm-dd')),
mat.matuserid,
mat.matname,
mat.matprice
FROM
matdatetable
LEFT JOIN mat ON matdatetable.sourceid = mat.matid
RESULT
matid matdate update matuserid matname matprice
-------------------------------------------------------------
1 2012-01-01 0:0:0:0 0111-1 aaa 100
1 2012-08-01 0:0:0:0 0111-1 aaa 125
1 2013-08-30 0:0:0:0 0111-1 aaa 150
2 2012-01-01 0:0:0:0 0222-1 bbb 130
2 2012-08-21 0:0:0:0 0222-1 bbb 110
2 2013-07-30 0:0:0:0 0222-1 bbb 100
3 2012-01-01 0:0:0:0 0565-1 ccc 100
3 2013-09-30 0:0:0:0 0565-1 ccc 230
But I want to. Results
matid matdate update matuserid matname matprice
------------------------------------------------------------------
1 2013-08-30 0:0:0:0 0111-1 aaa 150
2 2013-07-30 0:0:0:0 0222-1 bbb 100
3 2013-09-30 0:0:0:0 0565-1 ccc 230
SELECT DISTINCT ON (1)
t.sourceid AS matid
,t.matdateupdate::date AS matdate_update
,m.matuserid
,m.matname
,m.matprice
FROM matdatetable t
LEFT JOIN mat m ON m.matid = t.sourceid
ORDER BY 1, t.matdateupdate DESC;
Gives you the latest (according to matdateupdate) entry per sourceid. Your question isn't clear what you want exactly.
Using sourceid rather than matid, since you have a LEFT JOIN and matid could be NULL. Or your use of LEFT JOIN is incorrect ...
Explanation for DISTINCT ON in this related answer:
Select first row in each GROUP BY group?
t.matdateupdate::date casts your timestamp (assuming for lack of information) to date. That seems to be what you want. If you really need the redundant time 00:00, use datetrunc('day', t.matdateupdate) instead.