Is it possible for foxpro in sql statement to fill the winners_name column base on condition maximum score and id with different names - sql

Is it possible for foxpro in sql statement to add and fill a winners_name column base on condition maximum score and id with different names.
I have created a sql statement but it was not supported by foxpro, is there other alternative to do this rather than using a loop (I like sql statement for faster result even in 50k row lines)
SELECT * , ;
(SELECT TOP 1 doc_name FROM Table1 as b1 WHERE ALLTRIM(b1.id) = a.id ORDER BY b1.score DESC, b1.id) as WINNERS_NAME ;
FROM Table1 as a
I have only 1 table, with columns [ name, id, score ]
A sample table would be like this
NAME | ID | SCORE |
BEN | 101 | 5 |
KEN | 101 | 2 |
ZEN | 101 | 3 |
JEN | 103 | 4 |
REN | 103 | 3 |
LEN | 102 | 5 |
PEN | 102 | 4 |
ZEN | 102 | 3 |
The result would be like this (winners_name is tag on ID)
NAME | ID | SCORE | WINNERS_NAME
BEN | 101 | 5 | BEN
KEN | 101 | 2 | BEN
ZEN | 101 | 3 | BEN
JEN | 103 | 4 | PEN
REN | 103 | 3 | PEN
LEN | 102 | 5 | LEN
PEN | 103 | 5 | PEN
ZEN | 102 | 3 | LEN

Try this approach:
SELECT
a.NAME,
a.ID,
a.SCORE,
b.WINNERS_NAME
FROM Table1 a
INNER JOIN
(
SELECT t1.ID, t1.NAME AS WINNERS_NAME
FROM
(
SELECT ID, SCORE, MIN(NAME) AS NAME
FROM Table1
GROUP BY ID, SCORE
) t1
INNER JOIN
(
SELECT ID, MAX(SCORE) AS MAX_SCORE
FROM Table1
GROUP BY ID
) t2
ON t1.ID = t2.ID AND
t1.SCORE = t2.MAX_SCORE
) b
ON a.ID = b.ID
ORDER BY
a.ID;
Follow the link below for a demo running in MySQL (though the syntax should still work on FoxPro):
Demo

Related

All records from first table and extra records from second table

I have 2 tables where i want to take all records from 1st table and extra records from 2nd table.
Table A
+-----+---------+---------+
| ID | NAME | TASK |
+-----+---------+---------+
| 101 | Alan | Prepare |
+-----+---------+---------+
| 102 | Fabien | Approve |
+-----+---------+---------+
| 103 | Christy | Plan |
+-----+---------+---------+
| 104 | David | Approve |
+-----+---------+---------+
| 105 | Eric | Set |
+-----+---------+---------+
Table B
+-----+---------+---------+
| ID | NAME | TASK |
+-----+---------+---------+
| 101 | Richy | Prepare |
+-----+---------+---------+
| 103 | Girish | Plan |
+-----+---------+---------+
| 106 | Fleming | Approve |
+-----+---------+---------+
| 107 | Ian | Set |
+-----+---------+---------+
Expected output
+-----+---------+---------+
| ID | NAME | TASK |
+-----+---------+---------+
| 101 | Alan | Prepare |
+-----+---------+---------+
| 102 | Fabien | Approve |
+-----+---------+---------+
| 103 | Christy | Plan |
+-----+---------+---------+
| 104 | David | Approve |
+-----+---------+---------+
| 105 | Eric | Set |
+-----+---------+---------+
| 106 | Fleming | Approve |
+-----+---------+---------+
| 107 | Ian | Set |
+-----+---------+---------+
I have tried using LEFT JOIN. But i'm getting only all from left table.
select * from A left join B on A.ID=B.ID and B.ID is NULL
I have also tried UNION and UNION ALL but since Name can be different in 2 tables i'm getting both records. One solution could be using NOT IN but it will be big for me as i refer big queries as table A & B here. I dont know what i'm missing. It should be very simple but it is not striking me now. Please help.
I'm thinking a union with the help of ROW_NUMBER and a computed column:
WITH cte AS (
SELECT ID, NAME, TASK, 1 AS SRC FROM TableA
UNION ALL
SELECT ID, NAME, TASK, 2 FROM TableB
),
cte2 AS (
SELECT *, ROW_NUMBER() OVER (PARTITION BY ID ORDER BY SRC) rn
FROM cte
)
SELECT ID, NAME, TASK
FROM cte2
WHERE rn = 1;
The idea here is to build an intermediate table containing all records from both tables. We introduce a computed column which keeps track of the table source, and give A records a higher priority than B records. Using ROW_NUMBER allows us to select the A records over B records having the same ID.
Full outer join will work, as full out join will get all the matching and non matching records from both the tables
;with tablea as
(
select 101 as id, 'Alan' name, 'Prepare ' as task
union select 102 , 'Fabien' , 'Approve'
union select 103 , 'Christy' , 'Plan '
union select 104 , 'David' , 'Approve '
union select 105 , 'Eric' , 'Set ')
,tableb as (
select 101 as ID ,'Richy ' as NAME ,' Prepare ' as TASK
union select 103 ,'Girish ',' Plan '
union select 106 ,'Fleming',' Approve '
union select 107 ,'Ian ',' Set '
)
select isnull(a.id,b.id) as id, isnull(a.name,b.name) as name, isnull(a.task,b.TASK) from tablea a
full outer join tableb b on a.id = b.ID
Result

How to group results of a postgres table if any of the fields match?

I have a postgresql table of records Where every every record has a record in that table that matches it on at least one of three possible fields.
id | name | email | phone | product
----------------------------------------------------
1 | Rob A | foo#bar.com | 123 | 102
2 | Rob B | foo#bar.com | 323 | 102
3 | Rob C | foo#bcr.com | 123 | 102
4 | Rob A | foo#bdr.com | 523 | 102
5 | Rob A | foo#bar.com | 123 | 104
6 | Cat A | liz#bar.com | 999 | 102
7 | Cat B | lid#bar.com | 999 | 102
8 | Cat A | lib#bar.com | 991 | 102
I want to group tables any tables where the "product" matches and any of these other three fields, (name, email, phone). So the groups would end up looking like
id | name | email | phone | product
----------------------------------------------------
1 | Rob A | foo#bar.com | 123 | 102
2 | Rob B | foo#bar.com | 323 | 102
3 | Rob C | foo#bcr.com | 123 | 102
4 | Rob A | foo#bdr.com | 523 | 102
5 | Rob A | foo#bar.com | 123 | 104
6 | Cat A | liz#bar.com | 999 | 102
7 | Cat B | lid#bar.com | 999 | 102
8 | Cat A | lib#bar.com | 991 | 102
Is there any way to do this?
If we INNER JOIN the table with itself like
SELECT t1.id id1,
t2.id id2
FROM elbat t1
INNER JOIN elbat t2
ON t2.product = t1.product
AND (t2.name = t1.name
OR t2.email = t1.email
OR t2.phone = t1.phone)
AND t2.id > t1.id;
we'll have the lowest ID of a "group" with more than one row in id1. For each id1 the other members of the "group" are in id2.
That is, we can join the result from the query above, so that for each row the lowest ID of the "group" is joined. As rows, which build a "group" on their own or rows, which already have the lowest ID of a "group" won't find a partner row, we have to LEFT JOIN. We can now use the joined lowest ID, or the ID of a row itself, if there wasn't joined any partner row, as the "group" ID using coalesce().
SELECT coalesce(x.id1, t.id) groupid,
t.*
FROM elbat t
LEFT JOIN (SELECT t1.id id1,
t2.id id2
FROM elbat t1
INNER JOIN elbat t2
ON t2.product = t1.product
AND (t2.name = t1.name
OR t2.email = t1.email
OR t2.phone = t1.phone)
AND t2.id > t1.id) x
ON x.id2 = t.id
ORDER BY coalesce(x.id1, t.id);
As we also ordered by the "group" ID, we can sequentially traverse the result in any application and know, if the "group" ID changes, we're reading the first row of a new "group".
db<>fiddle

Teradata: Query the next lowest value of two columns for a given input

I have the following two tables:
TableA:
+---------+--------+
| name | nm_key |
+---------+--------+
| Bob | 1124 |
| Sally | 3278 |
| Frank | 6484 |
| Mary | 1125 |
| Annette | 2798 |
+---------+--------+
TableB:
+--------+----------+--------+
| nm_key | sequence | status |
+--------+----------+--------+
| 1124 | 33333 | 3 |
| 2798 | 11111 | 1 |
| 3278 | 12226 | 2 |
| 1125 | 24356 | 3 |
| 6484 | 12272 | 2 |
+--------+----------+--------+
Using the two tables, how do I write a Teradata SQL query that will return the name that has the next lowest status and the next lowest sequence for a name input? For example, an input of Bob will return Frank because the next lowest status is 2 with the next lowest sequence of 12272.
Try this:
Select * from table1
Left join table2 on table2.nm_key=table1.nm_key
Where status=ceil(status +.99)
Let's just focus on num_key here and table b. The name comes from joining the results. One method is a correlated subquery. The following gets the key
select b.*,
(select top 1 b2.nm_key
from b b2
where b2.status < b.status
order by b2.status desc, b2.sequence desc
) as prev_nm_key
from b;
Limiting to "Bob" and getting the name are minor adjustments to the logic.
EDIT:
That is a painful limitation. Here is one workaround:
select bb.*, b.nm_key
from (select b.*,
(select max(b2.status || ':' || b2.sequence) as statseq
from b b2
where b2.status < b.status
order by b2.status desc, b2.sequence desc
) as prev_nm_key
from b
) bb join
b
on (b.status || ':' || b.sequence) = bb.statseq;

I need a specific output

I have to get a specific output format from my tables.
Let's say I have a simple table with 2 columns name and value.
table T1
+---------------+------------------+
| Name | Value |
+---------------+------------------+
| stuff1 | 1 |
| stuff1 | 1 |
| stuff2 | 2 |
| stuff3 | 1 |
| stuff2 | 4 |
| stuff2 | 2 |
| stuff3 | 4 |
+---------------+------------------+
I know the values are in the interval 1-4. I group it by name and value and count number of the same rows as Number and get the following table:
table T2
+---------------+------------------+--------+
| Name | Value | Number |
+---------------+------------------+--------+
| stuff1 | 1 | 2 |
| stuff2 | 2 | 2 |
| stuff3 | 1 | 1 |
| stuff3 | 4 | 1 |
+---------------+------------------+--------+
Here is the part when I need your help! What should I do if I want to get these format?
table T3
+---------------+------------------+--------+
| Name | Value | Number |
+---------------+------------------+--------+
| stuff1 | 1 | 2 |
| stuff1 | 2 | 0 |
| stuff1 | 3 | 0 |
| stuff1 | 4 | 0 |
| stuff2 | 1 | 0 |
| stuff2 | 2 | 2 |
| stuff2 | 3 | 0 |
| stuff2 | 4 | 0 |
| stuff3 | 1 | 1 |
| stuff3 | 2 | 0 |
| stuff3 | 3 | 0 |
| stuff3 | 4 | 1 |
+---------------+------------------+--------+
Thanks for any suggestions!
You start with a cross join to generate all possible combinations and then left-join in the results from your existing query:
select n.name, v.value, coalesce(nv.cnt, 0) as "Number"
from (select distinct name from table t) n cross join
(select distinct value from table t) v left outer join
(select name, value, count(*) as cnt
from table t
group by name, value
) nv
on nv.name = n.name and nv.value = v.value;
Variation on the theme.
Differences between Gordon Linoff and Owen existing answers.
I prefer GROUP BY to get the Names rather than a DISTINCT. This may have better performance in a case like this. (See Rob Farley's still relevant article.)
I explode the subqueries into a series of CTEs for clarity.
I use table T2 as the question now labels the group results set instead of showing that as as subquery.
WITH PossibleValue AS (
SELECT 1 Value
UNION ALL
SELECT Value + 1
FROM PossibleValue
WHERE Value < 4
),
Name AS (
SELECT Name
FROM T1
GROUP BY Name
),
NameValue AS (
SELECT Name
,Value
FROM Name
CROSS JOIN
PossibleValue
)
SELECT nv.Name
,nv.Value
,ISNULL(T2.Number,0) Number
FROM NameValue nv
LEFT JOIN
T2 ON nv.Name = T2.Name
AND nv.Value = T2.Value
Yet another solution, this time using a Table Value Constructor in a CTE to build a table of name value combinations.
WITH value AS
( SELECT DISTINCT t.name, v.value
FROM T1 AS t
CROSS JOIN (VALUES (1),(2),(3),(4)) AS v (value)
)
SELECT v.name AS 'Name', v.value AS 'Value', COUNT(t.name) AS 'Number'
FROM value AS v
LEFT JOIN T1 AS t ON t.value = v.value AND t.name = v.name
GROUP BY v.name, v.value, t.name;

Find and update specific duplicates in MS SQL

given below table:
+----+---------+-----------+-------------+-------+
| ID | NAME | LAST NAME | PHONE | STATE |
+----+---------+-----------+-------------+-------+
| 1 | James | Vangohg | 04333989878 | NULL |
| 2 | Ashly | Baboon | 09898788909 | NULL |
| 3 | James | Vangohg | 04333989878 | NULL |
| 4 | Ashly | Baboon | 09898788909 | NULL |
| 5 | Michael | Foo | 02933889990 | NULL |
| 6 | James | Vangohg | 04333989878 | NULL |
+----+---------+-----------+-------------+-------+
I want to use MS SQL to find and update duplicate (based on name, last name and number) but only the earlier one(s). So desired result for above table is:
+----+---------+-----------+-------------+-------+
| ID | NAME | LAST NAME | PHONE | STATE |
+----+---------+-----------+-------------+-------+
| 1 | James | Vangohg | 04333989878 | DUPE |
| 2 | Ashly | Baboon | 09898788909 | DUPE |
| 3 | James | Vangohg | 04333989878 | DUPE |
| 4 | Ashly | Baboon | 09898788909 | NULL |
| 5 | Michael | Foo | 02933889990 | NULL |
| 6 | James | Vangohg | 04333989878 | NULL |
+----+---------+-----------+-------------+-------+
This query uses a CTE to apply a row number, where any number > 1 is a dupe of the row with the highest ID.
;WITH x AS
(
SELECT ID,NAME,[LAST NAME],PHONE,STATE,
ROW_NUMBER() OVER (PARTITION BY NAME,[LAST NAME],PHONE ORDER BY ID DESC)
FROM dbo.YourTable
)
UPDATE x SET STATE = CASE rn WHEN 1 THEN NULL ELSE 'DUPE' END;
Of course, I see no reason to actually update the table with this information; every time the table is touched, this data is stale and the query must be re-applied. Since you can derive this information at run-time, this should be part of a query, not constantly updated in the table. IMHO.
Try this statement.
LAST UPDATE:
update t1
set
t1.STATE = 'DUPE'
from
TableName t1
join
(
select name, last_name, phone, max(id) as id, count(id) as cnt
from
TableName
group by name, last_name, phone
having count(id) > 1
) t2 on ( t1.name = t2.name and t1.last_name = t2.last_name and t1.phone = t2.phone and t1.id < t2.id)
If my understanding of your requirements is correct, you want to update all of the STATE values to DUPE when there exists another row with a higher ID value that has the same NAME and LAST NAME. If so, use this:
update t set STATE = (case when sorted.RowNbr = 1 then null else 'DUPE' end)
from yourtable t
join (select
ID,
row_number() over
(partition by name, [last name], phone order by id desc) as RowNbr from yourtable)
sorted on sorted.ID = t.ID