我有两张桌子(表A和表B)。
这些列的列数不同 - 比如说表A有更多列。
如何将这两个表联合起来并为表B没有的列获取null?
答案 0 :(得分:169)
为具有较少列的表(如
)将额外列添加为nullSelect Col1, Col2, Col3, Col4, Col5 from Table1
Union
Select Col1, Col2, Col3, Null as Col4, Null as Col5 from Table2
答案 1 :(得分:6)
我来到这里并按照上面的回答。但是数据类型顺序不匹配导致错误。以下来自另一个答案的描述将会派上用场。
结果是否与表格中的列序列相同?因为oracle在列顺序中是严格的。以下示例产生错误:
create table test1_1790 (
col_a varchar2(30),
col_b number,
col_c date);
create table test2_1790 (
col_a varchar2(30),
col_c date,
col_b number);
select * from test1_1790
union all
select * from test2_1790;
ORA-01790:表达式必须与对应表达式具有相同的数据类型
正如您所看到的,错误的根本原因在于使用*作为列列表说明符所暗示的不匹配列排序。通过明确输入列列表可以轻松避免此类错误:
从test1_1790中选择col_a,col_b,col_c 联合所有 从test2_1790中选择col_a,col_b,col_c; 此错误的更常见情况是当您无意中交换(或转移)SELECT列表中的两个或更多列时:
select col_a, col_b, col_c from test1_1790
union all
select col_a, col_c, col_b from test2_1790;
或者,如果以上方法无法解决您的问题,请在如下列中创建ALIAS :(查询与您的查询不同,但此处的重点是如何添加别名)专栏。)
SELECT id_table_a,
desc_table_a,
table_b.id_user as iUserID,
table_c.field as iField
UNION
SELECT id_table_a,
desc_table_a,
table_c.id_user as iUserID,
table_c.field as iField
答案 2 :(得分:1)
对于任何多余的列(如果没有映射),则将其映射为null,如以下SQL查询一样
const Discord = require('discord.js');
const client = new Discord.Client();
const ffmpegInstaller = require('@ffmpeg-installer/ffmpeg');
const ffmpeg = require('fluent-ffmpeg');
ffmpeg.setFfmpegPath(ffmpegInstaller.path);
const fs = require('fs-extra')
const mergeStream = require('merge-stream');
const config = require('./config.json');
const { getAudioDurationInSeconds } = require('get-audio-duration');
const cp = require('child_process');
const path1 = require('path');
const Enmap = require('enmap');
const UserRecords = require("./models/userrecords.js")
const ServerRecords = require("./models/serverrecords.js")
let prefix = `$`
class Readable extends require('stream').Readable { _read() {} }
let recording = false;
let currently_recording = {};
let mp3Paths = [];
const silence_buffer = new Uint8Array(3840);
const express = require('express')
const app = express()
const port = 3000
const publicIP = require('public-ip')
const { program } = require('commander');
const { path } = require('@ffmpeg-installer/ffmpeg');
const version = '0.0.1'
program.version(version);
let debug = false
let runProd = false
let fqdn = "";
const mongoose = require("mongoose");
const MongoClient = require('mongodb').MongoClient;
mongoose.connect('SECRRET',{
useNewUrlParser: true
}, function(err){
if(err){
console.log(err);
}else{
console.log("Database connection initiated");
}
});
require("dotenv").config()
function bufferToStream(buffer) {
let stream = new Readable();
stream.push(buffer);
return stream;
}
client.commands = new Enmap();
client.on('ready', async () => {
console.log(`Logged in as ${client.user.tag}`);
let host = "localhost"
let ip = await publicIP.v4();
let protocol = "http";
if (!runProd) {
host = "localhost"
} else {
host = `35.226.244.186`;
}
fqdn = `${protocol}://${host}:${port}`
app.listen(port, `0.0.0.0`, () => {
console.log(`Listening on port ${port} for ${host} at fqdn ${fqdn}`)
})
});
let randomArr = []
let finalArrWithIds = []
let variable = 0
client.on('message', async message => {
console.log(`fuck`);
if(message.content === `$record`){
mp3Paths = []
finalArrWithIds = []
let membersToScrape = Array.from(message.member.voice.channel.members.values());
membersToScrape.forEach((member) => {
if(member.id === `749250882830598235`) {
console.log(`botid`);
}
else {
finalArrWithIds.push(member.id)
}
})
const randomNumber = Math.floor(Math.random() * 100)
randomArr = []
randomArr.push(randomNumber)
}
const generateSilentData = async (silentStream, memberID) => {
console.log(`recordingnow`)
while(recording) {
if (!currently_recording[memberID]) {
silentStream.push(silence_buffer);
}
await new Promise(r => setTimeout(r, 20));
}
return "done";
}
console.log(generateSilentData, `status`)
function generateOutputFile(channelID, memberID) {
const dir = `./recordings/${channelID}/${memberID}`;
fs.ensureDirSync(dir);
const fileName = `${dir}/${randomArr[0]}.aac`;
console.log(`${fileName} ---------------------------`);
return fs.createWriteStream(fileName);
}
if (!fs.existsSync("public")) {
fs.mkdirSync("public");
}
app.use("/public", express.static("./public"));
if (!message.guild) return;
if (message.content === config.prefix + config.record_command) {
if (recording) {
message.reply("bot is already recording");
return
}
if (message.member.voice.channel) {
recording = true;
const connection = await message.member.voice.channel.join();
const dispatcher = connection.play('./audio.mp3');
connection.on('speaking', (user, speaking) => {
if (speaking.has('SPEAKING')) {
currently_recording[user.id] = true;
} else {
currently_recording[user.id] = false;
}
})
let members = Array.from(message.member.voice.channel.members.values());
members.forEach((member) => {
if (member.id != client.user.id) {
let memberStream = connection.receiver.createStream(member, {mode : 'pcm', end : 'manual'})
let outputFile = generateOutputFile(message.member.voice.channel.id, member.id);
console.log(outputFile, `outputfile here`);
mp3Paths.push(outputFile.path);
silence_stream = bufferToStream(new Uint8Array(0));
generateSilentData(silence_stream, member.id).then(data => console.log(data));
let combinedStream = mergeStream(silence_stream, memberStream);
ffmpeg(combinedStream)
.inputFormat('s32le')
.audioFrequency(44100)
.audioChannels(2)
.on('error', (error) => {console.log(error)})
.audioCodec('aac')
.format('adts')
.pipe(outputFile)
}
})
} else {
message.reply('You need to join a voice channel first!');
}
}
if (message.content === config.prefix + config.stop_command) {
let date = new Date();
let dd = String(date.getDate()).padStart(2, '0');
let mm = String(date.getMonth() + 1).padStart(2, '0');
let yyyy = date.getFullYear();
date = mm + '/' + dd + '/' + yyyy;
let currentVoiceChannel = message.member.voice.channel;
if (currentVoiceChannel) {
recording = false;
await currentVoiceChannel.leave();
let mergedOutputFolder = './recordings/' + message.member.voice.channel.id + `/${randomArr[0]}/`;
fs.ensureDirSync(mergedOutputFolder);
let file_name = `${randomArr[0]}` + '.aac';
let mergedOutputFile = mergedOutputFolder + file_name;
let download_path = message.member.voice.channel.id + `/${randomArr[0]}/` + file_name;
let mixedOutput = new ffmpeg();
console.log(mp3Paths, `mp3pathshere`);
mp3Paths.forEach((mp3Path) => {
mixedOutput.addInput(mp3Path);
})
console.log(mp3Paths);
//mixedOutput.complexFilter('amix=inputs=2:duration=longest');
mixedOutput.complexFilter('amix=inputs=' + mp3Paths.length + ':duration=longest');
let processEmbed = new Discord.MessageEmbed().setTitle(`Audio Processing.`)
processEmbed.addField(`Audio processing starting now..`, `Processing Audio`)
processEmbed.setThumbnail(`https://media.discordapp.net/attachments/730811581046325348/748610998985818202/speaker.png`)
processEmbed.setColor(` #00FFFF`)
const processEmbedMsg = await message.channel.send(processEmbed)
async function saveMp3(mixedData, outputMixed) {
console.log(`${mixedData} MIXED `)
return new Promise((resolve, reject) => {
mixedData.on('error', reject).on('progress',
async (progress) => {
let processEmbedEdit = new Discord.MessageEmbed().setTitle(`Audio Processing.`)
processEmbedEdit.addField(`Processing: ${progress.targetSize} KB converted`, `Processing Audio`)
processEmbedEdit.setThumbnail(`https://media.discordapp.net/attachments/730811581046325348/748610998985818202/speaker.png`)
processEmbedEdit.setColor(` #00FFFF`)
processEmbedMsg.edit(processEmbedEdit)
console.log('Processing: ' + progress.targetSize + ' KB converted');
}).on('end', () => {
console.log('Processing finished !');
resolve()
}).saveToFile(outputMixed);
console.log(`${outputMixed} IT IS HERE`);
})
}
// mixedOutput.saveToFile(mergedOutputFile);
await saveMp3(mixedOutput, mergedOutputFile);
console.log(`${mixedOutput} IN HEREEEEEEE`);
// We saved the recording, now copy the recording
if (!fs.existsSync(`./public`)) {
fs.mkdirSync(`./public`);
}
let sourceFile = `${__dirname}/recordings/${download_path}`
console.log(`DOWNLOAD PATH HERE ${download_path}`)
const guildName = message.guild.id;
const serveExist = `/public/${guildName}`
if (!fs.existsSync(`.${serveExist}`)) {
fs.mkdirSync(`.${serveExist}`)
}
let destionationFile = `${__dirname}${serveExist}/${file_name}`
let errorThrown = false
try {
fs.copySync(sourceFile, destionationFile);
} catch (err) {
errorThrown = true
await message.channel.send(`Error: ${err.message}`)
}
const usersWithTag = finalArrWithIds.map(user => `\n <@${user}>`);
let timeSpent = await getAudioDurationInSeconds(`public/${guildName}/${file_name}`)
let timesSpentRound = Math.floor(timeSpent)
let finalTimeSpent = timesSpentRound / 60
let finalTimeForReal = Math.floor(finalTimeSpent)
if(!errorThrown){
//--------------------- server recording save START
class GeneralRecords {
constructor(generalLink, date, voice, time) {
this.generalLink = generalLink;
this.date = date;
this.note = `no note`;
this.voice = voice;
this.time = time
}
}
let newGeneralRecordClassObject = new GeneralRecords(`${fqdn}/public/${guildName}/${file_name}`, date, usersWithTag, finalTimeForReal)
let checkingServerRecord = await ServerRecords.exists({userid: `server`})
if(checkingServerRecord === true){
existingServerRecord = await ServerRecords.findOne({userid: `server`})
existingServerRecord.content.push(newGeneralRecordClassObject)
await existingServerRecord.save()
}
if(checkingServerRecord === false){
let serverRecord = new ServerRecords()
serverRecord.userid = `server`
serverRecord.content.push(newGeneralRecordClassObject)
await serverRecord.save()
}
//--------------------- server recording save STOP
}
//--------------------- personal recording section START
for( member of finalArrWithIds) {
let personal_download_path = message.member.voice.channel.id + `/${member}/` + file_name;
let sourceFilePersonal = `${__dirname}/recordings/${personal_download_path}`
let destionationFilePersonal = `${__dirname}${serveExist}/${member}/${file_name}`
await fs.copySync(sourceFilePersonal, destionationFilePersonal);
const user = client.users.cache.get(member);
console.log(user, `user here`);
try {
ffmpeg.setFfmpegPath(ffmpegInstaller.path);
ffmpeg(`public/${guildName}/${member}/${file_name}`)
.audioFilters('silenceremove=stop_periods=-1:stop_duration=1:stop_threshold=-90dB')
.output(`public/${guildName}/${member}/personal-${file_name}`)
.on(`end`, function () {
console.log(`DONE`);
})
.on(`error`, function (error) {
console.log(`An error occured` + error.message)
})
.run();
}
catch (error) {
console.log(error)
}
// ----------------- SAVING PERSONAL RECORDING TO DATABASE START
class PersonalRecords {
constructor(generalLink, personalLink, date, time) {
this.generalLink = generalLink;
this.personalLink = personalLink;
this.date = date;
this.note = `no note`;
this.time = time;
}
}
let timeSpentPersonal = await getAudioDurationInSeconds(`public/${guildName}/${file_name}`)
let timesSpentRoundPersonal = Math.floor(timeSpentPersonal)
let finalTimeSpentPersonal = timesSpentRoundPersonal / 60
let finalTimeForRealPersonal = Math.floor(finalTimeSpentPersonal)
let newPersonalRecordClassObject = new PersonalRecords(`${fqdn}/public/${guildName}/${file_name}`, `${fqdn}/public/${guildName}/${member}/personal-${file_name}`, date, finalTimeForRealPersonal)
let checkingUserRecord = await UserRecords.exists({userid: member})
if(checkingUserRecord === true){
existingUserRecord = await UserRecords.findOne({userid: member})
existingUserRecord.content.push(newPersonalRecordClassObject)
await existingUserRecord.save()
}
if(checkingUserRecord === false){
let newRecord = new UserRecords()
newRecord.userid = member
newRecord.content.push(newPersonalRecordClassObject)
await newRecord.save()
}
// ----------------- SAVING PERSONAL RECORDING TO DATABASE END
const endPersonalEmbed = new Discord.MessageEmbed().setTitle(`Your performance was amazing ! Review it here :D`)
endPersonalEmbed.setColor('#9400D3')
endPersonalEmbed.setThumbnail(`https://media.discordapp.net/attachments/730811581046325348/745381641324724294/vinyl.png`)
endPersonalEmbed.addField(`? Date`, `${date}`)
endPersonalEmbed.addField(`⏰ Time spent by you`, `${finalTimeForRealPersonal} minute(s)`)
endPersonalEmbed.addField(`? Download`, `${fqdn}/public/${guildName}/${member}/personal-${file_name}`)
endPersonalEmbed.setFooter(`Use \`$myrecordings\` to get a list of all your recordings !`)
user.send(endPersonalEmbed)
}
// ----------------- personal recording section OVER
const endEmbed = new Discord.MessageEmbed().setTitle(`I will be honest, that recording session was sick !`)
endEmbed.setColor('#9400D3')
endEmbed.addField(`?️ Voices`, usersWithTag)
endEmbed.addField(`⏰ Time spent`, `${finalTimeForReal} minute(s)`)
endEmbed.addField(`? Download`, `${fqdn}/public/${guildName}/${file_name}`)
endEmbed.setThumbnail(`https://media.discordapp.net/attachments/730811581046325348/745370416352067704/microphone.png`)
endEmbed.setFooter(`Check your DMs for a recording of your personal voice during this session.`)
message.channel.send(endEmbed)
} else {
message.reply('You need to join a voice channel first!');
}
}
if (message.content.indexOf(prefix) !== 0) return;
const args = message.content.slice(prefix.length).trim().split(/ +/g);
const command = args.shift().toLowerCase();
const cmd = client.commands.get(command);
if (!cmd) return;
cmd.run(client, message, args);
});
fs.readdir('./commands/', async (err, files) => {
if (err) return console.error;
files.forEach(file => {
if (!file.endsWith('.js')) return;
let props = require(`./commands/${file}`);
let cmdName = file.split('.')[0];
console.log(`Loaded command '${cmdName}'`);
// Register extra Listeners
client.commands.set(cmdName, props);
});
});
async function main() {
program.option('-debug')
program.option('-prod')
program.parse(process.argv)
console.log(program.opts())
if (program.Debug != undefined) {
debug = !debug
}
if (program.Prod != undefined) {
runProd = !runProd
}
if (runProd) {
client.login(process.env.DISCORD_TOKEN_PROD).catch(e => {
console.log("ERROR")
console.log(e)
})
} else {
client.login(process.env.DISCORD_TOKEN_TEST).catch(e => {
console.log("ERROR")
console.log(e)
})
}
}
main()
答案 3 :(得分:0)
如果只有1行,则可以使用join
Select t1.Col1, t1.Col2, t1.Col3, t2.Col4, t2.Col5 from Table1 t1 join Table2 t2;
答案 4 :(得分:0)
通常,在使用基于集合的运算符时,您需要具有相同的列数,因此Kangkan's answer是正确的。
SAS SQL具有特定的运算符来处理这种情况:
SAS(R) 9.3 SQL Procedure User's Guide
CORRESPONDING(CORR)关键字
仅在指定集合运算符时才使用CORRESPONDING关键字。 CORR使PROC SQL通过名称而不是按序位置来匹配表表达式中的列。除了OUTER UNION运算符外,名称不匹配的列将从结果表中排除。
SELECT * FROM tabA
OUTER UNION CORR
SELECT * FROM tabB;
针对:
+---+---+
| a | b |
+---+---+
| 1 | X |
| 2 | Y |
+---+---+
OUTER UNION CORR
+---+---+
| b | d |
+---+---+
| U | 1 |
+---+---+
<=>
+----+----+---+
| a | b | d |
+----+----+---+
| 1 | X | |
| 2 | Y | |
| | U | 1 |
+----+----+---+
U-SQL支持类似的概念:
外部
需要BY NAME子句和ON列表。与其他集合表达式相反,OUTER UNION的输出模式从两侧都包括匹配列和不匹配列。这就产生了这样一种情况,其中来自一侧的每一行都有仅出现在另一侧的“缺失列”。对于此类列,将为“缺少的单元格”提供默认值。对于可为空的类型,默认值为null;对于不可为空的类型,默认值为.Net。(例如,对于int,默认值为0)。
按人名
当与OUTER一起使用时,是必需的。该子句表明并集不是根据位置而是根据列的名称来匹配值。如果未指定BY NAME子句,则匹配将在位置进行。
如果ON子句包含“ *”符号(可以将其指定为列表的最后一个或唯一的成员),则允许使用ON子句中的名称之外的额外名称匹配,并且结果的列包括所有匹配项列按在左参数中出现的顺序排列。
和代码:
@result =
SELECT * FROM @left
OUTER UNION BY NAME ON (*)
SELECT * FROM @right;
编辑:
外部联合的概念由KQL支持:
种类:
内部-结果具有所有输入表共有的列子集。
外部-结果包含所有输入中出现的所有列。输入行未定义的单元格设置为null。
示例:
let t1 = datatable(col1:long, col2:string)
[1, "a",
2, "b",
3, "c"];
let t2 = datatable(col3:long)
[1,3];
t1 | union kind=outer t2;
输出:
+------+------+------+
| col1 | col2 | col3 |
+------+------+------+
| 1 | a | |
| 2 | b | |
| 3 | c | |
| | | 1 |
| | | 3 |
+------+------+------+