Logically create templates based on intersection table - sql

I'm not sure how to describe the question, but I'm trying to give suggestions on what codes to attribute to tariffs. I'm doing this in Oracle.
Here's my database structure:
CODE (
CODEID *PK NCHAR(10)
)
CODETARIFF (
TARIFFNO NCHAR(15) *PK *FK
CODEID NCHAR(10) *PK *FK
)
TARIFF (
TARIFFNO NCHAR(15) *PK
)
So I'm trying to logically make templates for what codes should be assigned to tariffs. I'm imagining showing something along the lines of: "6 tariffs also have these 2 codes associated with them"
I tried this, but the counts that are returned for each of the codes aren't really showing a template, they only really show incidences of when that one code appears with the two I've specified.
SELECT COUNT(*), CodeID
FROM CodeTariff
INNER JOIN (
SELECT TariffNo, COUNT(*)
FROM CodeTariff
WHERE CodeID IN ('ABC', 'DEF')
GROUP BY TariffNo
HAVING COUNT(*) > 1) SQ
ON CodeTariff.TariffNo = SQ.TariffNo
WHERE CodeID NOT IN ('ABC', 'DEF')
GROUP BY CodeTariff.CodeID
ORDER BY COUNT(*) DESC;
Sorry if this is confusing.
I don't know if this is even possible, but I'm looking for output like this:
Data:
TariffCode
TariffNo CodeID
1111 ABC
1111 DEF
2222 ABC
2222 DEF
2222 GHI
2222 JKL
3333 ABC
3333 DEF
3333 GHI
3333 JKL
Output: (when given tariff 1111)
CodesToAdd Count
GHI, JKL 2
So that I can display:
2 other tariffs have the codes GHI and JKL associated with them. Would you like to add these codes to tariff 1111?

Try these magics out:
SELECT Code, COUNT(*) AS Count
FROM (SELECT dbo.TariffCode.Tariff, dbo.TariffCode.Code
FROM dbo.TariffCode LEFT OUTER JOIN
(SELECT TariffCode_2.Tariff, TariffCode_2.Code
FROM dbo.TariffCode AS TariffCode_2 INNER JOIN
(SELECT Tariff, Code
FROM dbo.TariffCode AS TariffCode_1
WHERE (Tariff = '1111')) AS TariffsWithSharedCodes ON TariffCode_2.Code = TariffsWithSharedCodes.Code AND
TariffCode_2.Tariff <> '1111') AS MutualCodes ON dbo.TariffCode.Tariff = MutualCodes.Tariff AND
dbo.TariffCode.Code = MutualCodes.Code
WHERE (MutualCodes.Code IS NULL) AND (dbo.TariffCode.Tariff <> '1111')) AS MissingCodes
GROUP BY Code
ORDER BY Count DESC, Code
This is T-SQL, sorry, but you'll get the idea

Hope the script below can help you out. It will get all possible tariffs, not only for '1111':
with temp as (
select tariffno, tariffno2, codeid
from (
select distinct c1.tariffno, c2.tariffno as tariffno2, c2.codeid
from tariffcode c1
join tariffcode c2 on c1.tariffno != c2.tariffno and c1.codeid != c2.codeid
) c1
where
not exists (select 1 from tariffcode where tariffno = c1.tariffno and codeid = c1.codeid)
)
select tariffno, codeid, count(*) as cnt from temp group by tariffno, codeid;

Related

Mapping All Terminal IDs to Previous IDs

I have a table in SQL Server that contains a list of all ID migrations overtime. An individual's ID can change overtime, and this table helps us understand when the change occurs, and what the ID changes from/to. What I'd ultimately like is a way to list all of the previous IDs for the most recent ID (which I'm referring to as the terminal ID). I'm assuming this will require some sort of CTE, but my brain is in a bit of a fog as to how I should set this up.
CREATE TABLE #ExampleIdCrosswalk
(
CurrentId VARCHAR(3)
,PreviousId VARCHAR(3)
,PreviousIdObsoleteDate DATE
)
INSERT INTO #ExampleIdCrosswalk
VALUES
('DEF','ABC','2021-01-01')
,('WVU','ZYX','2021-01-01')
,('MNO','ONM','2021-02-01')
,('PPP','EEE','2021-02-01')
,('GHI','DEF','2021-03-01')
,('TSR','WVU','2021-03-01')
,('NRP','QRS','2021-03-01')
,('JKL','GHI','2021-04-01')
SELECT * FROM #ExampleIdCrosswalk
Ultimately, what I'd like to show is a table with all the terminal ID's along with each of their corresponding previous IDs.
Any help would be appreciated!
You can use a recursive CTE for this:
with cte as (
select currentid, previousid
from ExampleIdCrosswalk ec
where not exists (select 1 from ExampleIdCrosswalk ec2 where ec2.previousId = ec.currentid)
union all
select cte.currentid, ec.previousid
from cte join
ExampleIdCrosswalk ec
on ec.currentId = cte.previousId
)
select *
from cte;
Here is a db<>fiddle.
You can use a recursive CTE, as in:
with
n (last, curr, prev) as (
select currentid, currentid, previousid
from ExampleIdCrosswalk where currentid not in (
select previousid from ExampleIdCrosswalk
)
union all
select n.last, c.currentid, c.previousid
from n
join ExampleIdCrosswalk c on c.currentid = n.prev
)
select last, prev
from n
order by last, prev
Result:
last prev
----- ----
JKL ABC
JKL DEF
JKL GHI
MNO ONM
NRP QRS
PPP EEE
TSR WVU
TSR ZYX
See running example at db<>fiddle.

How I can apply Inner Join to filter the data in Sql Server

I have table in which I inserted all the liked places records.
Like:
I have table PlaceLikes;
Id placeId likedByUserID
1 ABC 1
2 DEF 1
3 ABC 2
4 FFF 2
Result: User 1 want to get all placeID that matches with itself.
Id placeId likedByUserID
3 ABC 2
Here User 2 with ABC placeId is similar with Requestor User ID 1.
So, How I can filter the data like this
You can use exists:
select t.*
from mytable t
where
t.likedByUserID <> 1
and exists (
select 1 from mytable t1 where t1.place_id = t.place_id and t1.likedByUserID = 1
)
I think this piece of query will be able to solve your problem statement as understood by me.
DECLARE #sample_name VARCHAR (10);
SET #sample_name = 'placeId to be searched'
SELECT Id, placeId, likedByUserID FROM demo_table dt
WHERE dt.placeId = #sample_name
Do let me know if this was helpful.

Extract non-existent values based on previous months?

I HAVE tb1
code Name sal_month
==== ===== ========
101 john 02/2017
102 mathe 02/2017
103 yara 02/2017
104 sara 02/2017
101 john 03/2017
102 mathe 03/2017
103 yara 03/2017
104 sara 03/2017
101 john 04/2017
103 yara 04/2017
In February all of them received salaries as well as March
How do I extract non-existent values based on previous months?
the result should be come
code sal_month
==== =======
102 04/2017
104 04/2017
Thank in advance
First I created this table:
create table #T(code int, sal_month varchar(10))
insert into #T values(101,'2/2017'),(102,'2/2017'),(103,'2/2017'),(104,'2/2017'),
(101,'3/2017'),(102,'3/2017'),(104,'3/2017'),(101,'4/2017'),(103,'4/2017')
Second, I executed this query:
SELECT code, Max(sal_Month)
From #T
Where code not in (select code from #T where sal_Month = (select Max(sal_Month) from #T))
Group by code
Then I got the following results:
Note: I am using SQL SERVER 2012
I think you can count salary_month grouped by id, something like this, and select the rows that shows less than 3 times.
select code, count (sal_month) from tb1
group by code
having count (sal_month) < 3
After that you join with initial table (just to filter the full rows which you need) on code.
So the final query will look like his:
select code, sal_month
from tb1 a
join (select code, count (sal_month) from tb1
group by code
having code < 3) X on a.code = X.code
Something like this:
DECLARE #DataSource TABLE
(
[code] INT
,[sal_month] VARCHAR(12)
);
INSERT #DataSource ([code], [sal_month])
VALUES (101, '2/2017')
,(102, '2/2017')
,(103, '2/2017')
,(104, '2/2017')
,(101, '3/2017')
,(102, '3/2017')
,(104, '3/2017')
,(101, '4/2017')
,(103, '4/2017');
WITH DataSource AS
(
SELECT *
,DENSE_RANK() OVER (ORDER BY [sal_month]) AS [MonthID]
,MAX([sal_month]) OVER () AS [MaxMonth]
FROM #DataSource DS1
)
SELECT DS1.[code]
,DS1.[sal_month]
FROM DataSource DS1
LEFT JOIN DataSource DS2
ON DS1.[code] = DS2.[code]
AND DS1.[MonthID] = DS2.[MonthID] - 1
LEFT JOIN DataSource DS3
ON DS1.[code] = DS3.[code]
AND DS1.[MonthID] = DS3.[MonthID] + 1
WHERE DS2.[code] IS NULL
AND DS3.[code] IS NOT NULL
AND DS1.[sal_month] <> DS1.[MaxMonth];
Some notes:
we need a way to sort the months and it is not easy as you are storing them in very unpractical way; you are not using a date/datetime column and your string is not a valid date; also, the string you are using is not good at all, because if you have [sal_month] from different years, we will not be able to sort them; you should think about this - one alternative is to use this format:
201512
201701
201702
201711
In this way we can sort by string.
in the core I am using ROW_NUMBER and sorting months as strings;
the idea is to look for all records, that have not exists in the next month, but have a record in the previous; at the same time, excluded records which are from the last month, as it's not possible for them to have record in the next month;
Try this:
select tb2.code, tb2.sal_month from tb
right join (
select code, sal_month, datepart(month, sal_month) + 1 as next_sal_month from tb) as tb2
on (tb.code = tb2.code and datepart(month, tb.sal_month) = tb2.next_sal_month)
where tb2.next_sal_month < 5 and tb.sal_month is null
In the result set there's one additional record: code 103 didn't receive salary in March, but did so in February, so it is included as well.
Here's SQL fiddle, to try :)
In the absence of more facts about your tables, create a cartesian product of the 2 axes of month & code, then left join the stored data. Then it is easy to identify missing items when no stored data exists when compared to every possible combination.
You might already have master tables of sal_month and/or code to use, if you do use those, but if not you can dynamically create them using select distinct as seen below.
create table tbl1 (code int, sal_month varchar(10))
insert into tbl1 values(101,'2/2017'),(102,'2/2017'),(103,'2/2017'),(104,'2/2017'),
(101,'3/2017'),(102,'3/2017'),(104,'3/2017'),(101,'4/2017'),(103,'4/2017')
select c.code, m.sal_month
from ( select distinct sal_month from tbl1 ) m
cross join ( select distinct code from tbl1 ) c
Left join tbl1 t on m.sal_month = t.sal_month and c.code = t.code
Where t.sal_month IS NULL
code | sal_month
---: | :--------
103 | 3/2017
102 | 4/2017
104 | 4/2017
dbfiddle here

Display Mismatched Rows belonging to Same table

Student table
Student Id Student Name
1 Vijay
2 Ram
Student Detail Table
Student ID Code StudentIdentityNumber
1 Primary 143
1 Secondary 143
1 Teritary 143
2 Primary 123
2 Secondary 123
2 Teritary 126
Output required
StudentID PrimaryIdentity SecondaryIdentity TeritaryIdentity
2 123 123 126
I just want this output. The output doesnt have StudentID 1 because for him primary secondary and teritary Numbers are same. Hope it is clear
Need simple solution. Yes Code column is Only three. Static only
Please find the below query:
Hope it helps you.
WITH cte
as (SELECT StudentID , [Primary],[Secondary],[Teritary]
FROM
(SELECT
StudentID , Code, StudentIdentityNumber FROM StudentDetail) s
Pivot
( max(StudentIdentityNumber) for Code in ( [Primary],[Secondary],[Teritary]) )as pvt
)
SELECT * FROM cte where cte.[Primary]<>cte.[Secondary] or cte.[Primary]<> cte.Teritary
select pvt.StudentID,
pvt.[Primary] PrimaryIdentity,
pvt.Secondary SecondaryIdentity,
pvt.Teritary TeritaryIdentity
from StudentDetail sd
pivot
(
max(StudentIdentityNumber)
for code in ([Primary],Secondary,Teritary)
) as pvt
where pvt.[Primary] <> pvt.Secondary
or pvt.Secondary <> pvt.Teritary
SELECT sd1.Student,
sd1.StudentIdentityNumber as Primary,
sd2.StudentIdentityNumber as Secondary,
sd3.StudentIdentityNumber as Teritary
FROM StudentDetail sd1
JOIN StudentDetail sd2
ON sd1.StudentID = sd2.StudentID
AND sd1.Code = 'Primary'
AND sd2.Code = 'Secondary'
JOIN StudentDetail sd3
ON sd2.StudentID = sd3.StudentID
AND sd2.Code = 'Teritary'
WHERE sd1.Primary <> sd2.Secondary
or sd1.Primary <> sd3.Teritary

how to combine two result sets without nulls

I have two result sets that I would like to combine , since I would like to send them as a dataset to my ssrs report.
I am currently doing :
Select Sum(Teamsales) as TS, Null as PS from ABC;
union
Select null as TS, Sum(ProdSales) From DEF;
I get an output like this :
123 NULL
NULL 456
Is there a way I can get an output as below ??
123 456
SELECT Sum(Teamsales) as TS,
(
SELECT Sum(ProdSales)
FROM DEF
) AS PS
FROM ABC
Maybe something like this?
select
sum(teamsales) as ts,
Sum(ProdSales) as ps
from
abc cross join
def
(Crossjoins are generally evil... But you could consider maybe to use more strict one.)
Most probably you would be having more than one row in each result set.
As you would apply a dimension in group by clause.
for example
You want to get total Team Sales and total Product sales for each branch then you should write.
Select ABC.BranchID, ABC.TS, DEF.PS
(Select BranchID, Sum(Teamsales) as TS from ABC group by BranchID) ABC
Inner Join
(Select BranchID, Sum(ProdSales) as PS From DEF group by BranchID) DEF
On ABC.BranchID = DEF.BranchID
Since these are both one-liners, you could just cross-join the results, giving you a single line:
SELECT SUM(Teamsales) as TS,
FROM abc
CROSS JOIN (SELECT SUMN(ProdSales) FROM def) t
Try this:
select sum(TS), sum(PS) from (
Select Sum(Teamsales) as TS, Null as PS from ABC
union all
Select null as TS, Sum(ProdSales) as PS From DEF
) as x