SQL- How to select data from two different table? - sql

I am working to select data from 2 different table but I can't figured out. If I use INNER JOIN it show noting. Any help are welcome and Thanks.
My First table:
CREATE TABLE P_N(
PN_ID int NOT NULL,
PN VARCHAR (1000),
primary key (PN_ID)
);
My second Table:
CREATE TABLE NAME (
NAME_ID VARCHAR(60) PRIMARY key,
NAME VARCHAR (40)
);
My select code :
SELECT DISTINCT NAME.NAME_ID, PN.PN_ID
FROM NAME
FULL JOIN P_N
ON PN.PN =NAME.NAME_ID;
If I use left or full Join this is the result:
NAME_ID PN_ID
nm0006300 NULL
nm0006400 NULL
nm0006500 NULL
nm0006600 NULL
nm0006700 NULL
AND if I use right join:
NAME_ID PN_ID
null 921691
null 921692
null 921693
null 921694
This is what I want the result to looks like For example:
NAME_ID PN_ID
nm0006300 921691
nm0006400 921692
nm0006500 921693
nm0006600 921694

You don't seem to have a JOIN key. You can add one with ROW_NUMBER():
SELECT n.NAME_ID, PN.PN_ID
FROM (SELECT n.*, ROW_NUMBER() OVER (ORDER BY NAME_ID) as seqnum
FROM NAME n
) n JOIN
(SELECT pn.*, ROW_NUMBER() OVER (ORDER BY PN) as seqnum
FROM P_N pn
) pn
ON PN.seqnum = n.seqnum;

try this
select DISTINCT NAME.NAME_ID, PN.PN_ID
from NAME,P_N as PN
where PN.PN =NAME.NAME_ID

Related

How to insert a column which sets unique id based on values in another column (SQL)?

I will create table where I will insert multiple values for different companies. Basically I have all values that are in the table below but I want to add a column IndicatorID which is linked to IndicatorName so that every indicator has a unique id. This will obviously not be a PrimaryKey.
I will insert the data with multiple selects:
CREATE TABLE abc
INSERT INTO abc
SELECT company_id, 'roe', roevalue, metricdate
FROM TABLE1
INSERT INTO abc
SELECT company_id, 'd/e', devalue, metricdate
FROM TABLE1
So, I don't know how to add the IndicatorID I mentioned above.
EDIT:
Here is how I populate my new table:
INSERT INTO table(IndicatorID, Indicator, Company, Value, Date)
SELECT [the ID that I need], 'NI_3y' as 'Indicator', t.Company, avg(t.ni) over (partition by t.Company order by t.reportdate rows between 2 preceding and current row) as 'ni_3y',
t.reportdate
FROM table t
LEFT JOIN IndicatorIDs i
ON i.Indicator = roe3 -- the part that is not working if I have separate indicatorID table
I am going to insert different indicators for the same companies. And I want indicatorID.
Your "indicator" is a proper entity in its own right. Create a table with all indicators:
create table indicators (
indicator_id int identity(1, 1) primary key,
indicator varchar(255)
);
Then, use the id only in this table. You can look up the value in the reference table.
Your inserts are then a little more complicated:
INSERT INTO indicators (indicator)
SELECT DISTINCT roevalue
FROM table1 t1
WHERE NOT EXISTS (SELECT 1 FROM indicators i2 WHERE i2.indicator = t1.roevalue);
Then:
INSERT INTO ABC (indicatorId, companyid, value, date)
SELECT i.indicatorId, t1.company, v.value, t1.metricdate
FROM table1 t1 CROSS APPLY
(VALUES ('roe', t1.roevalue), ('d/e', t1.devalue)
) v(indicator, value) JOIN
indicators i
ON i.indicator = v.indicator;
This process is called normalization and it is the typical way to store data in a database.
DDL and INSERT statement to create an indicators table with a unique constraint on indicator. Because the ind_id is intended to be a foreign key in the abc table it's created as a non-decomposable surrogate integer primary key using the IDENTITY property.
drop table if exists test_indicators;
go
create table test_indicators (
ind_id int identity(1, 1) primary key not null,
indicator varchar(20) unique not null);
go
insert into test_indicators(indicator) values
('NI'),
('ROE'),
('D/E');
The abc table depends on the ind_id column from indicators table as a foreign key reference. To populate the abc table company_id's are associated with ind_id's.
drop table if exists test_abc
go
create table test_abc(
a_id int identity(1, 1) primary key not null,
ind_id int not null references test_indicators(ind_id),
company_id int not null,
val varchar(20) null);
go
insert into test_abc(ind_id, company_id)
select ind_id, 102 from test_indicators where indicator='NI'
union all
select ind_id, 103 from test_indicators where indicator='ROE'
union all
select ind_id, 104 from test_indicators where indicator='D/E'
union all
select ind_id, 103 from test_indicators where indicator='NI'
union all
select ind_id, 105 from test_indicators where indicator='ROE'
union all
select ind_id, 102 from test_indicators where indicator='NI';
Query to get result
select i.ind_id, a.company_id, i.indicator, a.val
from test_abc a
join test_indicators i on a.ind_id=i.ind_id;
Output
ind_id company_id indicator val
1 102 NI NULL
2 103 ROE NULL
3 104 D/E NULL
1 103 NI NULL
2 105 ROE NULL
1 102 NI NULL
I was finally able to find the solution for my problem which seems to me very simple, although it took time and asking different people about it.
First I create my indicators table where I assign primary key for all indicators I have:
CREATE TABLE indicators (
indicator_id int identity(1, 1) primary key,
indicator varchar(255)
);
Then I populate easy without using any JOINs or CROSS APPLY. I don't know if this is optimal but it seems as the simplest choice:
INSERT INTO table(IndicatorID, Indicator, Company, Value, Date)
SELECT
(SELECT indicator_id from indicators i where i.indicator = 'NI_3y) as IndicatorID,
'NI_3y' as 'Indicator',
Company,
avg(ni) over (partition by Company order by reportdate rows between 2 preceding and current row) as ni_3y,
reportdate
FROM TABLE1

Useage of aggregate function but without having clause

Im have the following two tables created:
create table partei(
id int not null primary key ,
name varchar(20),
vorsitzender varchar(20)
);
create table abgeordneter(
name varchar(20),
partei int references partei ,
wahlkreis varchar(20)
)
How can I change this Select-Statement:
SELECT a.Partei
FROM Abgeordneter a, Partei p
WHERE a.Partei = p.ID
GROUP BY a.Partei
HAVING COUNT(a.Name) < 5
Into a statement which doesn't use the having clause, but delivers exactly the same results? Is it even possible?
You can use a subquery an eliminate the JOIN:
SELECT Partei
FROM (SELECT a.Partei, COUNT(*) as cnt
FROM Abgeordneter ap
GROUP BY a.Partei
) a
WHERE cnt < 5;

SQL 2014 - How to add incremental value for each row of non identity column

I have 2 tables (Dim & User). In Dim table, there is the EmpId column which has incremental values (1,2,..) but is not an identity column and the User table is in join with Dim table based on SalesKey.
There are 3 rows that are missing in Dim which exists in the User table. I want to insert the missing rows in Dim table, but the catch is while inserting the EmpId column needs to get incremental values for new rows.
So far queries I tried is as below, which gives me results in split, but I am not able to merge results in a single query, maybe nested subquery will help but not sure how?
Create table DimEmp
(
EmpId bigint not null,
SalesKey varchar(10),
EmpName varchar(100)
CONSTRAINT PK_DimEmp_EmpId PRIMARY KEY (EmpId)
)
GO
INSERT INTO DimEmp (EmpId,SalesKey,EmpName)
VALUES (1,'001A','John'), (2,'002B','Stephen')
GO
Create table [User]
(
UserId varchar(10),
EmpName varchar(100)
CONSTRAINT PK_User_UserId PRIMARY KEY (UserId)
)
GO
INSERT INTO [User] (UserId,EmpName)
VALUES ('001A','John'), ('002B','Stephen'),
('003C','Bruce'), ('004D','Clark'),('005E','Mitchel')
GO
SELECT u.UserId,u.EmpName
FROM [User] u
LEFT JOIN DimEmp d
ON d.SalesKey=u.UserId
WHERE d.SalesKey IS NULL -- prints missing 3 records of Dim
GO
SELECT 1 + EmpId + 1 AS NewincrEmpId,
( SELECT MAX(EmpId) FROM DimEmp
) AS MaxEmpid
FROM DimEmp -- inner query gives max empid and outer query increments value for each row
GO
Expected Output in Dim table after inserting 3 new records using INSERT INTO SELECT (subquery) statement
You will need to wrap the whole thing into a transaction.
Grab the max(EmpId) using serializable table lock, to make sure no other process adds/modifies EmpId
use row_number to get the new unique ids
Query:
begin tran
declare #maxid bigint
set #maxid =
(
select max(EmpId) from DimEmp with(serializable)
)
insert into DimEmp
(
EmpId,
SalesKey,
EmpName
)
select
isnull(#maxid, 0) +
row_number() over (order by u.UserId),
u.UserId,
u.EmpName
from
[User] as u
left join
DimEmp as d on
d.SalesKey = u.UserId
where
d.SalesKey is null
commit tran
Sounds like you got a serious design issue there.
For a quick fix you can use row_number() and add it to the maximum ID.
INSERT INTO [dimemp]
([empid],
[saleskey],
[empname])
SELECT (SELECT coalesce(max(de1.[empid]), 0)
FROM [dimemp] de1) + row_number() OVER (ORDER BY u1.[userid]),
u1.[userid],
u1.[empname]
FROM [user] u1
WHERE NOT EXISTS (SELECT *
FROM [dimemp] de2
WHERE de2.[saleskey] = u1.[userid]);
db<>fiddle
TRY: This is also better way of using OUTER APPLY to get max EmpId and ROW_NUMBER to get the desired output as below
SELECT ISNULL(tt.NewincrEmpId, 0)+ROW_NUMBER() OVER(ORDER BY u.UserId ASC) AS NewincrEmpId,
u.UserId,
u.EmpName
FROM User u
LEFT JOIN DimEmp d ON d.SalesKey=u.UserId
OUTER APPLY(SELECT MAX(de.EmpId) AS NewincrEmpId
FROM DimEmp de) tt
OUTPUT:
NewincrEmpId UserId EmpName
3 003C Bruce
4 004D Clark
5 005E Mitchel
WHERE d.SalesKey IS NULL

SQL query with GROUP BY and HAVING

I have a little problem in mi project, i'm trying to make a query on a single table but I'm not succeeding.
The table is this:
CREATE TABLE PARTITA(
COD_SFIDA VARCHAR (20) PRIMARY KEY,
DATA_P DATE NOT NULL,
RISULTATO CHAR (3) NOT NULL,
COD_DECK_IC VARCHAR (15),
COD_DECK_FC VARCHAR (15),
COD_EVT VARCHAR (15),
TAG_USR_IC VARCHAR (15),
TAG_USR_FC VARCHAR (15),
CONSTRAINT CHECK_RISULTATO CHECK (RISULTATO='0-0' OR RISULTATO='0-1' OR RISULTATO='1-0' OR RISULTATO='1-1'),
CONSTRAINT FK8 FOREIGN KEY (COD_DECK_IC, TAG_USR_IC) REFERENCES DECK (COD_DECK, TAG_USR) ON DELETE CASCADE,
CONSTRAINT FK17 FOREIGN KEY (COD_DECK_FC, TAG_USR_FC) REFERENCES DECK (COD_DECK, TAG_USR) ON DELETE CASCADE,
CONSTRAINT FK9 FOREIGN KEY (COD_EVT) REFERENCES TORNEO (COD_EVENTO) ON DELETE CASCADE
);
I would like to view the most used deck by each user.
this is the query I tried to do:
SELECT P.COD_DECK_FC, P.TAG_USR_FC, COUNT(P.COD_DECK_FC)
FROM PARTITA P
GROUP BY P.TAG_USR_FC, P.COD_DECK_FC
UNION
SELECT P.COD_DECK_IC, P.TAG_USR_IC, COUNT(P.COD_DECK_IC)
FROM PARTITA P
GROUP BY P.TAG_USR_IC, P.COD_DECK_IC
/
But I would like to view just the most used deck by each user and don't all the decks and how many times users used them.
How can I do?
I would like the query to show the tag_usr and the cod_deck that is used the most for all of this for each user
eg:
cod_deck tag_usr count(cod_deck)
------------- ----------- --------------
1 A1BE2 5
2 AE3NF 6
5 FNKJD 3
instead the previious query returns to me:
cod_deck tag_usr count(cod_deck)
------------- ----------- --------------
1 A1BE2 5
2 AE3NF 6
5 FNKJD 3
2 A1BE2 2
1 AE3NF 3
I just want that the query show me the users A1BE2 and AE3NF just one time, because the query have to select the most used deck of each user.
You don't want to select a field that you're counting. Try something like this:
SELECT P.COD_DECK_FC, P.TAG_USR_FC, COUNT(P.COD_SFIDA)
FROM PARTITA P
GROUP BY P.COD_DECK_FC, P.TAG_USR_FC
UNION
SELECT P.COD_DECK_IC, P.TAG_USR_IC, COUNT(P.COD_SFIDA)
FROM PARTITA P
GROUP BY P.COD_DECK_IC, P.TAG_USR_IC
That will list all of the combinations of COD_DECK_FC and TAG_USR_FC
and then number of times it appears in the table, and then do the same with COD_DECK_IC and TAG_USR_IC. It's not clear to me from your question exactly what you want, but I know that you shouldn't put a field in COUNT if you're selecting it.
If i understand correctly you need subquery with ranking function :
with t as (
select *, row_number() over (partition by cod_deck order by count desc) Seq
from (<union query>)
)
select *
from cte c
where seq = 1;
I think you want this:
with ct as (
select P.COD_DECK_FC as deck, P.TAG_USR_FC as usr, COUNT(P.COD_DECK_FC) as cnt
from partita p
group by P.TAG_USR_FC, P.COD_DECK_FC
union all
select P.COD_DECK_IC, P.TAG_USR_IC, COUNT(P.COD_DECK_IC)
from partita P
group by P.TAG_USR_IC, P.COD_DECK_IC
)
select ct.*
from (select ct.*,
row_number() over (partition by usr order by cnt desc) as seqnum
from ct
) ct
where seqnum = 1;
You can also shorten this using grouping sets:
select p.*
from (select coalesce(P.COD_DECK_FC, P.COD_DECK_IC) as deck,
coalesce(P.TAG_USR_FC, P.TAG_USR_IC) as usr,
count(*) as cnt,
row_number() over (partition by coalesce(P.TAG_USR_FC, P.TAG_USR_IC) order by count(*) desc) as seqnum
from partita p
group by grouping sets ( (P.TAG_USR_FC, P.COD_DECK_FC), P.TAG_USR_IC, P.COD_DECK_IC) )
) p
where seqnum = 1;

How to Verify Multiple Foreign Key Combination in a table with a Primary Key in another table

I Have a Specification Master Table with three columns
(
ID BIGINT PRIMARY KEY,
Name varchar,
Value varchar
)
a Product Master Table with two Columns
(
ID BIGINT PRIMARY KEY,
Name varchar
)
a Stock table with
(
StockID BIGINT PRIMARY KEY,
ProductID BIGINT FOREIGN KEY (Product.ID),
SpecGroupID BIGINT UNIQUE KEY,
Stock INT
)
a Specification Grouping Table with
(
GroupID BIGINT FOREIGN KEY (Stock.SpecGroupID),
SPecificationID BIGINT FOREIGN KEY (Specification.ID),
PRIMARY KEY (Composite)
)
Now I am looking for a combination of specification if it has any stock or not.
but could not find a logic to match exact combination.
The problem I am facing if a combination of specification has n specification associated with a stock.SpecGroupID in Specification Grouping Table.
While I am searching with a few less than those n specification combination it always returning the same SpecGroupID for n specs group.
Imagine I have a apple (Color: Red; Size:5; Weight:10) in stock
And someone is ordering for a apple (Color: Red; Size:5)
I Need to give a result: Not Available
Will this work for you?
SELECT Specification.ID SpecId
, Specification.Name SpecificationName
, Value SpecificationValue
, MAX(ISNULL(Stock.Stock,0)) HasStock
FROM
Specification
LEFT JOIN SpecificationGrouping sg
ON sg.SpecificationID = Specification.ID
LEFT JOIN Stock
ON GroupID = SpecGroupID
GROUP BY Specification.ID
, Specification.Name
, Value
First cte Groups tell me the specifications of each group.
Second cte GroupDetail join all properties in a single string like this Color|Red,Size|5,Weight|10
Third cte OrderDetail is just the test input. in this sample 6 and 9 are orders.
Last query. Try to find one item on stocks with exact detail as the order
If a specification isn't on stocks I assume is an order, here 6 doesn't have item on stock so produce all null and 9 does have stock and return the StockValue.
SQL Fiddle Demo
WITH Groups as
(
SELECT *
FROM SpecificationGrouping SG
INNER JOIN Specification S
ON Sg.SPecificationID = S.ID
),
GroupDetail as
(
Select distinct ST2.GroupID,
substring(
(
Select ','+ ST1.Name + '|' + ST1.Value AS [text()]
From Groups ST1
Where ST1.GroupID = ST2.GroupID
ORDER BY ST1.Name
For XML PATH ('')
), 2, 1000) [Detail]
From Groups ST2
),
OrderDetail as
(
SELECT Detail
FROM GroupDetail
WHERE GroupID = 9
)
SELECT S.SpecGroupID, S.Stock, G.[Detail]
FROM Stock S
INNER JOIN GroupDetail G
ON S.SpecGroupID = G.GroupID
RIGHT JOIN OrderDetail O
ON O.Detail = G.Detail
Output for 9
| SpecGroupID | Stock | Detail |
|-------------|-------|----------------------------|
| 3 | 5 | Color|Red,Size|5,Weight|10 |